diff options
Diffstat (limited to 'framework/Web/UI')
123 files changed, 42598 insertions, 42598 deletions
diff --git a/framework/Web/UI/ActiveControls/TActiveButton.php b/framework/Web/UI/ActiveControls/TActiveButton.php index aaa10168..15b33692 100644 --- a/framework/Web/UI/ActiveControls/TActiveButton.php +++ b/framework/Web/UI/ActiveControls/TActiveButton.php @@ -1,132 +1,132 @@ -<?php
-/**
- * TActiveButton class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveButton is the active control counter part to TButton.
- *
- * When a TActiveButton is clicked, rather than a normal post back request a
- * callback request is initiated.
- *
- * The {@link onCallback OnCallback} event is raised during a callback request
- * and it is raise <b>after</b> the {@link onClick OnClick} event.
- *
- * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate}
- * property is true, changing the {@link setText Text} property during callback request
- * will update the button's caption upon callback response completion.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
- * is true, it will invoke the page's {@link TPage::validate validate}
- * method first. It will raise {@link onClick OnClick} event first
- * and then the {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->raisePostBackEvent($param);
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Updates the button text on the client-side if the
- * {@link setEnableUpdate EnableUpdate} property is set to true.
- * @param string caption of the button
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveButton';
- }
-}
-
+<?php +/** + * TActiveButton class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveButton is the active control counter part to TButton. + * + * When a TActiveButton is clicked, rather than a normal post back request a + * callback request is initiated. + * + * The {@link onCallback OnCallback} event is raised during a callback request + * and it is raise <b>after</b> the {@link onClick OnClick} event. + * + * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate} + * property is true, changing the {@link setText Text} property during callback request + * will update the button's caption upon callback response completion. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, by calling this constructor. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveCallbackControl standard callback control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Raises the callback event. This method is required by + * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation} + * is true, it will invoke the page's {@link TPage::validate validate} + * method first. It will raise {@link onClick OnClick} event first + * and then the {@link onCallback OnCallback} event. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $this->raisePostBackEvent($param); + $this->onCallback($param); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } + + /** + * Updates the button text on the client-side if the + * {@link setEnableUpdate EnableUpdate} property is set to true. + * @param string caption of the button + */ + public function setText($value) + { + parent::setText($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value); + } + + /** + * Override parent implementation, no javascript is rendered here instead + * the javascript required for active control is registered in {@link addAttributesToRender}. + */ + protected function renderClientControlScript($writer) + { + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * @return string corresponding javascript class name for this TActiveButton. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveButton'; + } +} + diff --git a/framework/Web/UI/ActiveControls/TActiveClientScript.php b/framework/Web/UI/ActiveControls/TActiveClientScript.php index 423918d9..2e58b6b0 100755 --- a/framework/Web/UI/ActiveControls/TActiveClientScript.php +++ b/framework/Web/UI/ActiveControls/TActiveClientScript.php @@ -1,82 +1,82 @@ -<?php
-/**
- * TActiveClientScript class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveClientScript class
- *
- * This is the active counterpart of the {@link TClientScript} class.
- *
- * TActiveClientScript has the ability to render itself on ajax
- * callbacks. This means that every variable or function declared in javascript
- * code will be available to the page.
- *
- * Beware that when rendered on normal (postback) or ajax callbacks, some
- * javascript code won't behave in the same way.
- * When rendered as part of a normal/postback response, scripts will execute instantly
- * where they are in the page and in a synchronous fashion.
- * Instead, when they are rendered as part of a callback response,
- * they will be executed when all DOM modifications are complete and any dynamic
- * script file includes are loaded, out-of-band and practically all blocks at once,
- * regardless of where they actually occour in the original template/markup code.
- * This can potentially hurt compatibility and graceful fallback.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- * @since 3.2
- */
-
-class TActiveClientScript extends TClientScript
-{
- /**
- * Renders the custom script file.
- * @param THtmLWriter the renderer
- */
- protected function renderCustomScriptFile($writer)
- {
- if(($scriptUrl = $this->getScriptUrl())!=='')
- {
- if($this->getPage()->getIsCallback())
- {
- $cs = $this->getPage()->getClientScript();
- $uniqueid=$this->ClientID.'_custom';
- if(!$cs->isScriptFileRegistered($uniqueid))
- $cs->registerScriptFile($uniqueid, $scriptUrl);
- } else {
- $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
- }
- }
- }
-
- /**
- * Registers the body content as javascript.
- * @param THtmlWriter the renderer
- */
- protected function renderCustomScript($writer)
- {
- if($this->getHasControls())
- {
- if($this->getPage()->getIsCallback())
- {
- $extWriter= $this->getPage()->getResponse()->createHtmlWriter();
- $extWriter->write("/*<![CDATA[*/\n");
- $this->renderChildren($extWriter);
- $extWriter->write("\n/*]]>*/");
- $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
- } else {
- $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
- $this->renderChildren($writer);
- $writer->write("\n/*]]>*/\n</script>\n");
- }
- }
- }
-}
+<?php +/** + * TActiveClientScript class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $ + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveClientScript class + * + * This is the active counterpart of the {@link TClientScript} class. + * + * TActiveClientScript has the ability to render itself on ajax + * callbacks. This means that every variable or function declared in javascript + * code will be available to the page. + * + * Beware that when rendered on normal (postback) or ajax callbacks, some + * javascript code won't behave in the same way. + * When rendered as part of a normal/postback response, scripts will execute instantly + * where they are in the page and in a synchronous fashion. + * Instead, when they are rendered as part of a callback response, + * they will be executed when all DOM modifications are complete and any dynamic + * script file includes are loaded, out-of-band and practically all blocks at once, + * regardless of where they actually occour in the original template/markup code. + * This can potentially hurt compatibility and graceful fallback. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $ + * @package System.Web.UI.ActiveControls + * @since 3.2 + */ + +class TActiveClientScript extends TClientScript +{ + /** + * Renders the custom script file. + * @param THtmLWriter the renderer + */ + protected function renderCustomScriptFile($writer) + { + if(($scriptUrl = $this->getScriptUrl())!=='') + { + if($this->getPage()->getIsCallback()) + { + $cs = $this->getPage()->getClientScript(); + $uniqueid=$this->ClientID.'_custom'; + if(!$cs->isScriptFileRegistered($uniqueid)) + $cs->registerScriptFile($uniqueid, $scriptUrl); + } else { + $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n"); + } + } + } + + /** + * Registers the body content as javascript. + * @param THtmlWriter the renderer + */ + protected function renderCustomScript($writer) + { + if($this->getHasControls()) + { + if($this->getPage()->getIsCallback()) + { + $extWriter= $this->getPage()->getResponse()->createHtmlWriter(); + $extWriter->write("/*<![CDATA[*/\n"); + $this->renderChildren($extWriter); + $extWriter->write("\n/*]]>*/"); + $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter); + } else { + $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n"); + $this->renderChildren($writer); + $writer->write("\n/*]]>*/\n</script>\n"); + } + } + } +} diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index 8a0c8aec..7e7a82fe 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -1,575 +1,575 @@ -<?php
-/**
- * TActiveControlAdapter and TCallbackPageStateTracker class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/*
- * Load common active control options.
- */
-Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
-
-/**
- * TActiveControlAdapter class.
- *
- * Customize the parent TControl class for active control classes.
- * TActiveControlAdapter instantiates a common base active control class
- * throught the {@link getBaseActiveControl BaseActiveControl} property.
- * The type of BaseActiveControl can be provided in the second parameter in the
- * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
- * the control adapted implements ICallbackEventHandler.
- *
- * TActiveControlAdapter will tracking viewstate changes to update the
- * corresponding client-side properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveControlAdapter extends TControlAdapter
-{
- /**
- * @var string base active control class name.
- */
- private $_activeControlType;
- /**
- * @var TBaseActiveControl base active control instance.
- */
- private $_baseActiveControl;
- /**
- * @var TCallbackPageStateTracker view state tracker.
- */
- private $_stateTracker;
-
- /**
- * Constructor.
- * @param IActiveControl active control to adapt.
- * @param string Base active control class name.
- */
- public function __construct(IActiveControl $control, $baseCallbackClass=null)
- {
- parent::__construct($control);
- $this->setBaseControlClass($baseCallbackClass);
- }
-
- /**
- * @param string base active control instance
- */
- protected function setBaseControlClass($type)
- {
- if($type===null)
- {
- if($this->getControl() instanceof ICallbackEventHandler)
- $this->_activeControlType = 'TBaseActiveCallbackControl';
- else
- $this->_activeControlType = 'TBaseActiveControl';
- }
- else
- $this->_activeControlType = $type;
- }
-
- /**
- * Publish the ajax script
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- }
-
- /**
- * Renders the callback client scripts.
- */
- public function render($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('ajax');
- $this->renderCallbackClientScripts();
- if($this->_control->getVisible(false))
- {
- parent::render($writer);
- } else {
- $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>");
- }
- }
-
- /**
- * Register the callback clientscripts and sets the post loader IDs.
- */
- protected function renderCallbackClientScripts()
- {
- $cs = $this->getPage()->getClientScript();
- $key = 'Prado.CallbackRequest.addPostLoaders';
- if(!$cs->isEndScriptRegistered($key))
- {
- $data = $this->getPage()->getPostDataLoaders();
- if(count($data) > 0)
- {
- $options = TJavaScript::encode($data,false);
- $script = "Prado.CallbackRequest.addPostLoaders({$options});";
- $cs->registerEndScript($key, $script);
- }
- }
- }
-
- /**
- * @param TBaseActiveControl change base active control
- */
- public function setBaseActiveControl($control)
- {
- $this->_baseActiveControl=$control;
- }
-
- /**
- * @return TBaseActiveControl Common active control options.
- */
- public function getBaseActiveControl()
- {
- if($this->_baseActiveControl===null)
- {
- $type = $this->_activeControlType;
- $this->_baseActiveControl = new $type($this->getControl());
- }
- return $this->_baseActiveControl;
- }
-
- /**
- * @return boolean true if the viewstate needs to be tracked.
- */
- protected function getIsTrackingPageState()
- {
- if($this->getPage()->getIsCallback())
- {
- $target = $this->getPage()->getCallbackEventTarget();
- if($target instanceof ICallbackEventHandler)
- {
- $client = $target->getActiveControl()->getClientSide();
- return $client->getEnablePageStateUpdate();
- }
- }
- return false;
- }
-
- /**
- * Starts viewstate tracking if necessary after when controls has been loaded
- */
- public function onLoad($param)
- {
- if($this->getIsTrackingPageState())
- {
- $this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
- $this->_stateTracker->trackChanges();
- }
- parent::onLoad($param);
- }
-
- /**
- * Saves additional persistent control state. Respond to viewstate changes
- * if necessary.
- */
- public function saveState()
- {
- if(($this->_stateTracker!==null)
- && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
- {
- $this->_stateTracker->respondToChanges();
- }
- parent::saveState();
- }
-
- /**
- * @return TCallbackPageStateTracker state tracker.
- */
- public function getStateTracker()
- {
- return $this->_stateTracker;
- }
-}
-
-/**
- * TCallbackPageStateTracker class.
- *
- * Tracking changes to the page state during callback.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackPageStateTracker
-{
- /**
- * @var TMap new view state data
- */
- private $_states;
- /**
- * @var TMap old view state data
- */
- private $_existingState;
- /**
- * @var TControl the control tracked
- */
- private $_control;
- /**
- * @var object null object.
- */
- private $_nullObject;
-
- /**
- * Constructor. Add a set of default states to track.
- * @param TControl control to track.
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_existingState = new TMap;
- $this->_nullObject = new stdClass;
- $this->_states = new TMap;
- $this->addStatesToTrack();
- }
-
- /**
- * Add a list of view states to track. Each state is added
- * to the StatesToTrack property with the view state name as key.
- * The value should be an array with two enteries. The first entery
- * is the name of the class that will calculate the state differences.
- * The second entry is a php function/method callback that handles
- * the changes in the viewstate.
- */
- protected function addStatesToTrack()
- {
- $states = $this->getStatesToTrack();
- $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
- $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
- $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
- $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
- $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
- $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
- $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
- }
-
- /**
- * @return TMap list of viewstates to track.
- */
- protected function getStatesToTrack()
- {
- return $this->_states;
- }
-
- /**
- * Start tracking view state changes. The clone function on objects are called
- * for those viewstate having an object as value.
- */
- public function trackChanges()
- {
- foreach($this->_states as $name => $value)
- {
- $obj = $this->_control->getViewState($name);
- $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
- }
- }
-
- /**
- * @return array list of viewstate and the changed data.
- */
- protected function getChanges()
- {
- $changes = array();
- foreach($this->_states as $name => $details)
- {
- $new = $this->_control->getViewState($name);
- $old = $this->_existingState[$name];
- if($new !== $old)
- {
- $diff = new $details[0]($new, $old, $this->_nullObject);
- if(($change = $diff->getDifference()) !== $this->_nullObject)
- $changes[] = array($details[1],array($change));
- }
- }
- return $changes;
- }
-
- /**
- * For each of the changes call the corresponding change handlers.
- */
- public function respondToChanges()
- {
- foreach($this->getChanges() as $change)
- call_user_func_array($change[0], $change[1]);
- }
-
- /**
- * @return TCallbackClientScript callback client scripting
- */
- protected function client()
- {
- return $this->_control->getPage()->getCallbackClient();
- }
-
- /**
- * Updates the tooltip.
- * @param string new tooltip
- */
- protected function updateToolTip($value)
- {
- $this->client()->setAttribute($this->_control, 'title', $value);
- }
-
- /**
- * Updates the tab index.
- * @param integer tab index
- */
- protected function updateTabIndex($value)
- {
- $this->client()->setAttribute($this->_control, 'tabindex', $value);
- }
-
- /**
- * Updates the modifier access key
- * @param string access key
- */
- protected function updateAccessKey($value)
- {
- $this->client()->setAttribute($this->_control, 'accesskey', $value);
- }
-
- /**
- * Hides or shows the control on the client-side. The control must be
- * already rendered on the client-side.
- * @param boolean true to show the control, false to hide.
- */
- protected function updateVisible($visible)
- {
- if($visible === false)
- $this->client()->replaceContent($this->_control,"<span id=\"".$this->_control->getClientID()."\" style=\"display:none\" ></span>");
- else
- $this->client()->replaceContent($this->_control,$this->_control);
- }
-
- /**
- * Enables or Disables the control on the client-side.
- * @param boolean true to enable the control, false to disable.
- */
- protected function updateEnabled($enable)
- {
- $this->client()->setAttribute($this->_control, 'disabled', $enable===false);
- }
-
- /**
- * Updates the CSS style on the control on the client-side.
- * @param array list of new CSS style declarations.
- */
- protected function updateStyle($style)
- {
- if($style['CssClass']!==null)
- $this->client()->setAttribute($this->_control, 'class', $style['CssClass']);
- if(count($style['Style']) > 0)
- $this->client()->setStyle($this->_control, $style['Style']);
- }
-
- /**
- * Updates/adds a list of attributes on the control.
- * @param array list of attribute name-value pairs.
- */
- protected function updateAttributes($attributes)
- {
- foreach($attributes as $name => $value)
- $this->client()->setAttribute($this->_control, $name, $value);
- }
-}
-
-/**
- * Calculates the viewstate changes during the request.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TViewStateDiff
-{
- /**
- * @var mixed updated viewstate
- */
- protected $_new;
- /**
- * @var mixed viewstate value at the begining of the request.
- */
- protected $_old;
- /**
- * @var object null value.
- */
- protected $_null;
-
- /**
- * Constructor.
- * @param mixed updated viewstate value.
- * @param mixed viewstate value at the begining of the request.
- * @param object representing the null value.
- */
- public function __construct($new, $old, $null)
- {
- $this->_new = $new;
- $this->_old = $old;
- $this->_null = $null;
- }
-
- /**
- * @return mixed view state changes, nullObject if no difference.
- */
- public abstract function getDifference();
-}
-
-/**
- * TScalarDiff class.
- *
- * Calculate the changes to a scalar value.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TScalarDiff extends TViewStateDiff
-{
- /**
- * @return mixed update viewstate value.
- */
- public function getDifference()
- {
- if(gettype($this->_new) === gettype($this->_old)
- && $this->_new === $this->_old)
- return $this->_null;
- else
- return $this->_new;
- }
-}
-
-/**
- * TStyleDiff class.
- *
- * Calculates the changes to the Style properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TStyleDiff extends TViewStateDiff
-{
- /**
- * @param TStyle control style
- * @return array all the style properties combined.
- */
- protected function getCombinedStyle($obj)
- {
- if(!($obj instanceof TStyle))
- return array();
- $style = $obj->getStyleFields();
- $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
- if($obj->hasFont())
- $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
- return $style;
- }
-
- /**
- * @param string CSS custom style string.
- * @param array CSS style as name-value array.
- */
- protected function getStyleFromString($string)
- {
- $style = array();
- if(!is_string($string)) return $style;
-
- foreach(explode(';',$string) as $sub)
- {
- $arr=explode(':',$sub);
- if(isset($arr[1]) && trim($arr[0])!=='')
- $style[trim($arr[0])] = trim($arr[1]);
- }
- return $style;
- }
-
- /**
- * @return string changes to the CSS class name.
- */
- protected function getCssClassDiff()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) && $this->_new->hasCssClass()
- ? $this->_new->getCssClass() : null;
- }
- else
- {
- return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
- $this->_new->getCssClass() : null;
- }
- }
-
- /**
- * @return array list of changes to the control style.
- */
- protected function getStyleDiff()
- {
- $diff = array_diff_assoc(
- $this->getCombinedStyle($this->_new),
- $this->getCombinedStyle($this->_old));
- return count($diff) > 0 ? $diff : null;
- }
-
- /**
- * @return array list of changes to the control style and CSS class name.
- */
- public function getDifference()
- {
- if($this->_new===null)
- return $this->_null;
- else
- {
- $css = $this->getCssClassDiff();
- $style = $this->getStyleDiff();
- if(($css!==null) || ($style!==null))
- return array('CssClass' => $css, 'Style' => $style);
- else
- $this->_null;
- }
- }
-}
-
-/**
- * TAttributesDiff class.
- *
- * Calculate the changes to attributes collection.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TMapCollectionDiff extends TViewStateDiff
-{
- /**
- * @return array updates to the attributes collection.
- */
- public function getDifference()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
- }
- else
- {
- $new = $this->_new->toArray();
- $old = $this->_old->toArray();
- $diff = array_diff_assoc($new, $old);
- return count($diff) > 0 ? $diff : $this->_null;
- }
- }
-}
-
+<?php +/** + * TActiveControlAdapter and TCallbackPageStateTracker class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/* + * Load common active control options. + */ +Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl'); + +/** + * TActiveControlAdapter class. + * + * Customize the parent TControl class for active control classes. + * TActiveControlAdapter instantiates a common base active control class + * throught the {@link getBaseActiveControl BaseActiveControl} property. + * The type of BaseActiveControl can be provided in the second parameter in the + * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if + * the control adapted implements ICallbackEventHandler. + * + * TActiveControlAdapter will tracking viewstate changes to update the + * corresponding client-side properties. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveControlAdapter extends TControlAdapter +{ + /** + * @var string base active control class name. + */ + private $_activeControlType; + /** + * @var TBaseActiveControl base active control instance. + */ + private $_baseActiveControl; + /** + * @var TCallbackPageStateTracker view state tracker. + */ + private $_stateTracker; + + /** + * Constructor. + * @param IActiveControl active control to adapt. + * @param string Base active control class name. + */ + public function __construct(IActiveControl $control, $baseCallbackClass=null) + { + parent::__construct($control); + $this->setBaseControlClass($baseCallbackClass); + } + + /** + * @param string base active control instance + */ + protected function setBaseControlClass($type) + { + if($type===null) + { + if($this->getControl() instanceof ICallbackEventHandler) + $this->_activeControlType = 'TBaseActiveCallbackControl'; + else + $this->_activeControlType = 'TBaseActiveControl'; + } + else + $this->_activeControlType = $type; + } + + /** + * Publish the ajax script + */ + public function onPreRender($param) + { + parent::onPreRender($param); + } + + /** + * Renders the callback client scripts. + */ + public function render($writer) + { + $this->getPage()->getClientScript()->registerPradoScript('ajax'); + $this->renderCallbackClientScripts(); + if($this->_control->getVisible(false)) + { + parent::render($writer); + } else { + $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>"); + } + } + + /** + * Register the callback clientscripts and sets the post loader IDs. + */ + protected function renderCallbackClientScripts() + { + $cs = $this->getPage()->getClientScript(); + $key = 'Prado.CallbackRequest.addPostLoaders'; + if(!$cs->isEndScriptRegistered($key)) + { + $data = $this->getPage()->getPostDataLoaders(); + if(count($data) > 0) + { + $options = TJavaScript::encode($data,false); + $script = "Prado.CallbackRequest.addPostLoaders({$options});"; + $cs->registerEndScript($key, $script); + } + } + } + + /** + * @param TBaseActiveControl change base active control + */ + public function setBaseActiveControl($control) + { + $this->_baseActiveControl=$control; + } + + /** + * @return TBaseActiveControl Common active control options. + */ + public function getBaseActiveControl() + { + if($this->_baseActiveControl===null) + { + $type = $this->_activeControlType; + $this->_baseActiveControl = new $type($this->getControl()); + } + return $this->_baseActiveControl; + } + + /** + * @return boolean true if the viewstate needs to be tracked. + */ + protected function getIsTrackingPageState() + { + if($this->getPage()->getIsCallback()) + { + $target = $this->getPage()->getCallbackEventTarget(); + if($target instanceof ICallbackEventHandler) + { + $client = $target->getActiveControl()->getClientSide(); + return $client->getEnablePageStateUpdate(); + } + } + return false; + } + + /** + * Starts viewstate tracking if necessary after when controls has been loaded + */ + public function onLoad($param) + { + if($this->getIsTrackingPageState()) + { + $this->_stateTracker = new TCallbackPageStateTracker($this->getControl()); + $this->_stateTracker->trackChanges(); + } + parent::onLoad($param); + } + + /** + * Saves additional persistent control state. Respond to viewstate changes + * if necessary. + */ + public function saveState() + { + if(($this->_stateTracker!==null) + && $this->getControl()->getActiveControl()->canUpdateClientSide(true)) + { + $this->_stateTracker->respondToChanges(); + } + parent::saveState(); + } + + /** + * @return TCallbackPageStateTracker state tracker. + */ + public function getStateTracker() + { + return $this->_stateTracker; + } +} + +/** + * TCallbackPageStateTracker class. + * + * Tracking changes to the page state during callback. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackPageStateTracker +{ + /** + * @var TMap new view state data + */ + private $_states; + /** + * @var TMap old view state data + */ + private $_existingState; + /** + * @var TControl the control tracked + */ + private $_control; + /** + * @var object null object. + */ + private $_nullObject; + + /** + * Constructor. Add a set of default states to track. + * @param TControl control to track. + */ + public function __construct($control) + { + $this->_control = $control; + $this->_existingState = new TMap; + $this->_nullObject = new stdClass; + $this->_states = new TMap; + $this->addStatesToTrack(); + } + + /** + * Add a list of view states to track. Each state is added + * to the StatesToTrack property with the view state name as key. + * The value should be an array with two enteries. The first entery + * is the name of the class that will calculate the state differences. + * The second entry is a php function/method callback that handles + * the changes in the viewstate. + */ + protected function addStatesToTrack() + { + $states = $this->getStatesToTrack(); + $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible')); + $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled')); + $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes')); + $states['Style'] = array('TStyleDiff', array($this, 'updateStyle')); + $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex')); + $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip')); + $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey')); + } + + /** + * @return TMap list of viewstates to track. + */ + protected function getStatesToTrack() + { + return $this->_states; + } + + /** + * Start tracking view state changes. The clone function on objects are called + * for those viewstate having an object as value. + */ + public function trackChanges() + { + foreach($this->_states as $name => $value) + { + $obj = $this->_control->getViewState($name); + $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj; + } + } + + /** + * @return array list of viewstate and the changed data. + */ + protected function getChanges() + { + $changes = array(); + foreach($this->_states as $name => $details) + { + $new = $this->_control->getViewState($name); + $old = $this->_existingState[$name]; + if($new !== $old) + { + $diff = new $details[0]($new, $old, $this->_nullObject); + if(($change = $diff->getDifference()) !== $this->_nullObject) + $changes[] = array($details[1],array($change)); + } + } + return $changes; + } + + /** + * For each of the changes call the corresponding change handlers. + */ + public function respondToChanges() + { + foreach($this->getChanges() as $change) + call_user_func_array($change[0], $change[1]); + } + + /** + * @return TCallbackClientScript callback client scripting + */ + protected function client() + { + return $this->_control->getPage()->getCallbackClient(); + } + + /** + * Updates the tooltip. + * @param string new tooltip + */ + protected function updateToolTip($value) + { + $this->client()->setAttribute($this->_control, 'title', $value); + } + + /** + * Updates the tab index. + * @param integer tab index + */ + protected function updateTabIndex($value) + { + $this->client()->setAttribute($this->_control, 'tabindex', $value); + } + + /** + * Updates the modifier access key + * @param string access key + */ + protected function updateAccessKey($value) + { + $this->client()->setAttribute($this->_control, 'accesskey', $value); + } + + /** + * Hides or shows the control on the client-side. The control must be + * already rendered on the client-side. + * @param boolean true to show the control, false to hide. + */ + protected function updateVisible($visible) + { + if($visible === false) + $this->client()->replaceContent($this->_control,"<span id=\"".$this->_control->getClientID()."\" style=\"display:none\" ></span>"); + else + $this->client()->replaceContent($this->_control,$this->_control); + } + + /** + * Enables or Disables the control on the client-side. + * @param boolean true to enable the control, false to disable. + */ + protected function updateEnabled($enable) + { + $this->client()->setAttribute($this->_control, 'disabled', $enable===false); + } + + /** + * Updates the CSS style on the control on the client-side. + * @param array list of new CSS style declarations. + */ + protected function updateStyle($style) + { + if($style['CssClass']!==null) + $this->client()->setAttribute($this->_control, 'class', $style['CssClass']); + if(count($style['Style']) > 0) + $this->client()->setStyle($this->_control, $style['Style']); + } + + /** + * Updates/adds a list of attributes on the control. + * @param array list of attribute name-value pairs. + */ + protected function updateAttributes($attributes) + { + foreach($attributes as $name => $value) + $this->client()->setAttribute($this->_control, $name, $value); + } +} + +/** + * Calculates the viewstate changes during the request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +abstract class TViewStateDiff +{ + /** + * @var mixed updated viewstate + */ + protected $_new; + /** + * @var mixed viewstate value at the begining of the request. + */ + protected $_old; + /** + * @var object null value. + */ + protected $_null; + + /** + * Constructor. + * @param mixed updated viewstate value. + * @param mixed viewstate value at the begining of the request. + * @param object representing the null value. + */ + public function __construct($new, $old, $null) + { + $this->_new = $new; + $this->_old = $old; + $this->_null = $null; + } + + /** + * @return mixed view state changes, nullObject if no difference. + */ + public abstract function getDifference(); +} + +/** + * TScalarDiff class. + * + * Calculate the changes to a scalar value. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TScalarDiff extends TViewStateDiff +{ + /** + * @return mixed update viewstate value. + */ + public function getDifference() + { + if(gettype($this->_new) === gettype($this->_old) + && $this->_new === $this->_old) + return $this->_null; + else + return $this->_new; + } +} + +/** + * TStyleDiff class. + * + * Calculates the changes to the Style properties. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TStyleDiff extends TViewStateDiff +{ + /** + * @param TStyle control style + * @return array all the style properties combined. + */ + protected function getCombinedStyle($obj) + { + if(!($obj instanceof TStyle)) + return array(); + $style = $obj->getStyleFields(); + $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle())); + if($obj->hasFont()) + $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString())); + return $style; + } + + /** + * @param string CSS custom style string. + * @param array CSS style as name-value array. + */ + protected function getStyleFromString($string) + { + $style = array(); + if(!is_string($string)) return $style; + + foreach(explode(';',$string) as $sub) + { + $arr=explode(':',$sub); + if(isset($arr[1]) && trim($arr[0])!=='') + $style[trim($arr[0])] = trim($arr[1]); + } + return $style; + } + + /** + * @return string changes to the CSS class name. + */ + protected function getCssClassDiff() + { + if($this->_old===null) + { + return ($this->_new!==null) && $this->_new->hasCssClass() + ? $this->_new->getCssClass() : null; + } + else + { + return $this->_old->getCssClass() !== $this->_new->getCssClass() ? + $this->_new->getCssClass() : null; + } + } + + /** + * @return array list of changes to the control style. + */ + protected function getStyleDiff() + { + $diff = array_diff_assoc( + $this->getCombinedStyle($this->_new), + $this->getCombinedStyle($this->_old)); + return count($diff) > 0 ? $diff : null; + } + + /** + * @return array list of changes to the control style and CSS class name. + */ + public function getDifference() + { + if($this->_new===null) + return $this->_null; + else + { + $css = $this->getCssClassDiff(); + $style = $this->getStyleDiff(); + if(($css!==null) || ($style!==null)) + return array('CssClass' => $css, 'Style' => $style); + else + $this->_null; + } + } +} + +/** + * TAttributesDiff class. + * + * Calculate the changes to attributes collection. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TMapCollectionDiff extends TViewStateDiff +{ + /** + * @return array updates to the attributes collection. + */ + public function getDifference() + { + if($this->_old===null) + { + return ($this->_new!==null) ? $this->_new->toArray() : $this->_null; + } + else + { + $new = $this->_new->toArray(); + $old = $this->_old->toArray(); + $diff = array_diff_assoc($new, $old); + return count($diff) > 0 ? $diff : $this->_null; + } + } +} + diff --git a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php index 9e09eb88..df8f45d9 100644 --- a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php +++ b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php @@ -1,265 +1,265 @@ -<?php
-/**
- * TActiveCustomValidator class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TActiveCustomValidator Class
- *
- * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
- * validation event. The client-side uses callbacks to raise
- * the {@link onServerValidate onServerValidate} event.
- *
- * Beware that the {@link onServerValidate onServerValidate} may be
- * raised when the control to validate on the client side
- * changes value, that is, the server validation may be called many times.
- *
- * After the callback or postback, the {@link onServerValidate onServerValidate}
- * is raised once more. The {@link getIsCallback IsCallback} property
- * will be true when validation is made during a callback request.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidator extends TCustomValidator
- implements ICallbackEventHandler, IActiveControl
-{
- /**
- * @var boolean true if validation is made during a callback request.
- */
- private $_isCallback = false;
-
- /**
- * @return boolean true if validation is made during a callback request.
- */
- public function getIsCallback()
- {
- return $this->_isCallback;
- }
-
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client validation function is NOT supported.
- */
- public function setClientValidationFunction($value)
- {
- throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
- get_class($this));
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface. The {@link onServerValidate
- * OnServerValidate} event is raised first and then the
- * {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->_isCallback = true;
- $result = $this->onServerValidate($param->getCallbackParameter());
- $param->setResponseData($result);
- $this->onCallback($param);
- }
-
- /**
- * @param boolean whether the value is valid; this method will trigger a clientside update if needed
- */
- public function setIsValid($value)
- {
- parent::setIsValid($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.updateActiveCustomValidator';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=TBaseValidator::getClientScriptOptions();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-
- /**
- * Sets the text for the error message. Updates client-side erorr message.
- * @param string the error message
- */
- public function setErrorMessage($value)
- {
- parent::setErrorMessage($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.setErrorMessage';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
-
- /**
- * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
- * @return boolean whether client-side validation is enabled.
- */
- public function getEnableClientScript()
- {
- return true;
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- TBaseValidator::registerClientScriptValidator();
- }
-
- /**
- * @return string corresponding javascript class name for this this.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveCustomValidator';
- }
-}
-
-/**
- * Custom Validator callback client side options class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidatorClientSide extends TCallbackClientSide
-{
- /**
- * @return string javascript code for client-side OnValidate event.
- */
- public function getOnValidate()
- {
- return $this->getOption('OnValidate');
- }
-
- /**
- * Client-side OnValidate validator event is raise before the validators
- * validation functions are called.
- * @param string javascript code for client-side OnValidate event.
- */
- public function setOnValidate($javascript)
- {
- $this->setFunction('OnValidate', $javascript);
- }
-
- /**
- * Client-side OnSuccess event is raise after validation is successfull.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnSuccess event.
- */
- public function setOnValidationSuccess($javascript)
- {
- $this->setFunction('OnValidationSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnSuccess event.
- */
- public function getOnValidationSuccess()
- {
- return $this->getOption('OnValidationSuccess');
- }
-
- /**
- * Client-side OnError event is raised after validation failure.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnError event.
- */
- public function setOnValidationError($javascript)
- {
- $this->setFunction('OnValidationError', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnError event.
- */
- public function getOnValidationError()
- {
- return $this->getOption('OnValidationError');
- }
-
- /**
- * @param boolean true to revalidate when the control to validate changes value.
- */
- public function setObserveChanges($value)
- {
- $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return boolean true to observe changes.
- */
- public function getObserveChanges()
- {
- $changes = $this->getOption('ObserveChanges');
- return ($changes===null) ? true : $changes;
- }
-}
+<?php +/** + * TActiveCustomValidator class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide'); + +/** + * TActiveCustomValidator Class + * + * Performs custom validation using only server-side {@link onServerValidate onServerValidate} + * validation event. The client-side uses callbacks to raise + * the {@link onServerValidate onServerValidate} event. + * + * Beware that the {@link onServerValidate onServerValidate} may be + * raised when the control to validate on the client side + * changes value, that is, the server validation may be called many times. + * + * After the callback or postback, the {@link onServerValidate onServerValidate} + * is raised once more. The {@link getIsCallback IsCallback} property + * will be true when validation is made during a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveCustomValidator extends TCustomValidator + implements ICallbackEventHandler, IActiveControl +{ + /** + * @var boolean true if validation is made during a callback request. + */ + private $_isCallback = false; + + /** + * @return boolean true if validation is made during a callback request. + */ + public function getIsCallback() + { + return $this->_isCallback; + } + + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, by calling this constructor. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide); + } + + /** + * @return TBaseActiveCallbackControl standard callback control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Client validation function is NOT supported. + */ + public function setClientValidationFunction($value) + { + throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported', + get_class($this)); + } + + /** + * Raises the callback event. This method is required by {@link + * ICallbackEventHandler} interface. The {@link onServerValidate + * OnServerValidate} event is raised first and then the + * {@link onCallback OnCallback} event. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $this->_isCallback = true; + $result = $this->onServerValidate($param->getCallbackParameter()); + $param->setResponseData($result); + $this->onCallback($param); + } + + /** + * @param boolean whether the value is valid; this method will trigger a clientside update if needed + */ + public function setIsValid($value) + { + parent::setIsValid($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + $client = $this->getPage()->getCallbackClient(); + $func = 'Prado.Validation.updateActiveCustomValidator'; + $client->callClientFunction($func, array($this, $value)); + } + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options=TBaseValidator::getClientScriptOptions(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } + + /** + * Sets the text for the error message. Updates client-side erorr message. + * @param string the error message + */ + public function setErrorMessage($value) + { + parent::setErrorMessage($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + $client = $this->getPage()->getCallbackClient(); + $func = 'Prado.Validation.setErrorMessage'; + $client->callClientFunction($func, array($this, $value)); + } + } + + + /** + * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work. + * @return boolean whether client-side validation is enabled. + */ + public function getEnableClientScript() + { + return true; + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + TBaseValidator::registerClientScriptValidator(); + } + + /** + * @return string corresponding javascript class name for this this. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveCustomValidator'; + } +} + +/** + * Custom Validator callback client side options class. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveCustomValidatorClientSide extends TCallbackClientSide +{ + /** + * @return string javascript code for client-side OnValidate event. + */ + public function getOnValidate() + { + return $this->getOption('OnValidate'); + } + + /** + * Client-side OnValidate validator event is raise before the validators + * validation functions are called. + * @param string javascript code for client-side OnValidate event. + */ + public function setOnValidate($javascript) + { + $this->setFunction('OnValidate', $javascript); + } + + /** + * Client-side OnSuccess event is raise after validation is successfull. + * This will override the default client-side validator behaviour. + * @param string javascript code for client-side OnSuccess event. + */ + public function setOnValidationSuccess($javascript) + { + $this->setFunction('OnValidationSuccess', $javascript); + } + + /** + * @return string javascript code for client-side OnSuccess event. + */ + public function getOnValidationSuccess() + { + return $this->getOption('OnValidationSuccess'); + } + + /** + * Client-side OnError event is raised after validation failure. + * This will override the default client-side validator behaviour. + * @param string javascript code for client-side OnError event. + */ + public function setOnValidationError($javascript) + { + $this->setFunction('OnValidationError', $javascript); + } + + /** + * @return string javascript code for client-side OnError event. + */ + public function getOnValidationError() + { + return $this->getOption('OnValidationError'); + } + + /** + * @param boolean true to revalidate when the control to validate changes value. + */ + public function setObserveChanges($value) + { + $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value)); + } + + /** + * @return boolean true to observe changes. + */ + public function getObserveChanges() + { + $changes = $this->getOption('ObserveChanges'); + return ($changes===null) ? true : $changes; + } +} diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php index 32d91cd2..c05b1744 100644 --- a/framework/Web/UI/ActiveControls/TActiveLabel.php +++ b/framework/Web/UI/ActiveControls/TActiveLabel.php @@ -80,7 +80,7 @@ class TActiveLabel extends TLabel implements IActiveControl /** * Adds attribute id to the renderer. - * @param THtmlWriter the writer used for the rendering purpose
+ * @param THtmlWriter the writer used for the rendering purpose */ protected function addAttributesToRender($writer) { $writer->addAttribute('id',$this->getClientID()); diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php index 726dd8ba..144f621e 100644 --- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php +++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -1,401 +1,401 @@ -<?php
-/**
- * TActivePageAdapter, TCallbackErrorHandler and TInvalidCallbackException class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load callback response adapter class.
- */
-Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TActivePageAdapter class.
- *
- * Callback request handler.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePageAdapter extends TControlAdapter
-{
- /**
- * Callback response data header name.
- */
- const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
- /**
- * Callback response client-side action header name.
- */
- const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
- /**
- * Callback error header name.
- */
- const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
- /**
- * Callback page state header name.
- */
- const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
- /**
- * Script list header name.
- */
- const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
- /**
- * Stylesheet list header name.
- */
- const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
- /**
- * Hidden field list header name.
- */
- const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
-
- /**
- * Callback redirect url header name.
- */
- const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
-
- /**
- * @var ICallbackEventHandler callback event handler.
- */
- private $_callbackEventTarget;
- /**
- * @var mixed callback event parameter.
- */
- private $_callbackEventParameter;
- /**
- * @var TCallbackClientScript callback client script handler
- */
- private $_callbackClient;
-
- private $_controlsToRender=array();
-
- /**
- * Constructor, trap errors and exception to let the callback response
- * handle them.
- */
- public function __construct(TPage $control)
- {
- parent::__construct($control);
-
- //TODO: can this be done later?
- $response = $this->getApplication()->getResponse();
- $response->setAdapter(new TCallbackResponseAdapter($response));
-
- $this->trapCallbackErrorsExceptions();
- }
-
- /**
- * Process the callback request.
- * @param THtmlWriter html content writer.
- */
- public function processCallbackEvent($writer)
- {
- Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->raiseCallbackEvent();
- }
-
- /**
- * Register a control for defered render() call.
- * @param TControl control for defered rendering
- * @param THtmlWriter the renderer
- */
- public function registerControlToRender($control,$writer)
- {
- $id = $control->getUniqueID();
- if(!isset($this->_controlsToRender[$id]))
- $this->_controlsToRender[$id] = array($control,$writer);
- }
-
- /**
- * Trap errors and exceptions to be handled by TCallbackErrorHandler.
- */
- protected function trapCallbackErrorsExceptions()
- {
- $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
- }
-
- /**
- * Render the callback response.
- * @param THtmlWriter html content writer.
- */
- public function renderCallbackResponse($writer)
- {
- Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
- $this->renderResponse($writer);
- else
- $this->redirect($url);
- }
-
- /**
- * Redirect url on the client-side using javascript.
- * @param string new url to load.
- */
- protected function redirect($url)
- {
- Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
- //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url);
- }
-
- /**
- * Renders the callback response by adding additional callback data and
- * javascript actions in the header and page state if required.
- * @param THtmlWriter html content writer.
- */
- protected function renderResponse($writer)
- {
- Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- //renders all the defered render() calls.
- foreach($this->_controlsToRender as $rid => $forRender)
- $forRender[0]->render($forRender[1]);
-
- $response = $this->getResponse();
-
- //send response data in header
- if($response->getHasAdapter())
- {
- $responseData = $response->getAdapter()->getResponseData();
- if($responseData!==null)
- {
- $data = TJavaScript::jsonEncode($responseData);
-
- $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
- //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data);
- }
- }
-
- //sends page state in header
- if(($handler = $this->getCallbackEventTarget()) !== null)
- {
- if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
- {
- $pagestate = $this->getPage()->getClientState();
- $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
- //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate);
- }
- }
-
- //safari must receive at least 1 byte of data.
- $writer->write(" ");
-
- //output the end javascript
- if($this->getPage()->getClientScript()->hasEndScripts())
- {
- $writer = $response->createHtmlWriter();
- $this->getPage()->getClientScript()->renderEndScripts($writer);
- $this->getPage()->getCallbackClient()->evaluateScript($writer);
- }
-
- //output the actions
- $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
- $actions = TJavaScript::jsonEncode($executeJavascript);
- $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
- //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions);
-
-
- $cs = $this->Page->getClientScript();
-
- // collect all stylesheet file references
- $stylesheets = $cs->getStyleSheetUrls();
- if (count($stylesheets)>0)
- $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
-
- // collect all script file references
- $scripts = $cs->getScriptUrls();
- if (count($scripts)>0)
- $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
-
- // collect all hidden field references
- $fields = $cs->getHiddenFields();
- if (count($fields)>0)
- $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
- }
-
- /**
- * Appends data or javascript code to the body content surrounded with delimiters
- */
- private function appendContentPart($response, $delimiter, $data)
- {
- $content = $response->createHtmlWriter();
- $content->getWriter()->setBoundary($delimiter);
- $content->write($data);
- }
-
- /**
- * Trys to find the callback event handler and raise its callback event.
- * @throws TInvalidCallbackException if call back target is not found.
- * @throws TInvalidCallbackException if the requested target does not
- * implement ICallbackEventHandler.
- */
- private function raiseCallbackEvent()
- {
- if(($callbackHandler=$this->getCallbackEventTarget())!==null)
- {
- if($callbackHandler instanceof ICallbackEventHandler)
- {
- $param = $this->getCallbackEventParameter();
- $result = new TCallbackEventParameter($this->getResponse(), $param);
- $callbackHandler->raiseCallbackEvent($result);
- }
- else
- {
- throw new TInvalidCallbackException(
- 'callback_invalid_handler', $callbackHandler->getUniqueID());
- }
- }
- else
- {
- $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- throw new TInvalidCallbackException('callback_invalid_target', $target);
- }
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- if($this->_callbackEventTarget===null)
- {
- $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- if(!empty($eventTarget))
- $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
- }
- return $this->_callbackEventTarget;
- }
-
- /**
- * 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->_callbackEventTarget=$control;
- }
-
- /**
- * Gets callback parameter. JSON encoding is assumed.
- * @return string postback event parameter
- */
- public function getCallbackEventParameter()
- {
- if($this->_callbackEventParameter===null)
- {
- $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
- if(strlen($param) > 0)
- $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param);
- }
- return $this->_callbackEventParameter;
- }
-
- /**
- * @param mixed postback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->_callbackEventParameter=$value;
- }
-
- /**
- * Gets the callback client script handler. It handlers the javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript callback client handler.
- */
- public function getCallbackClientHandler()
- {
- if($this->_callbackClient===null)
- $this->_callbackClient = new TCallbackClientScript;
- return $this->_callbackClient;
- }
-}
-
-/**
- * TCallbackErrorHandler class.
- *
- * Captures errors and exceptions and send them back during callback response.
- * When the application is in debug mode, the error and exception stack trace
- * are shown. A TJavascriptLogger must be present on the client-side to view
- * the error stack trace.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackErrorHandler extends TErrorHandler
-{
- /**
- * Displays the exceptions to the client-side TJavascriptLogger.
- * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
- * @param Exception exception details.
- */
- protected function displayException($exception)
- {
- if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
- {
- $response = $this->getApplication()->getResponse();
- $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception));
- $response->setStatusCode(500, 'Internal Server Error');
- $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace);
- }
- else
- {
- error_log("Error happened while processing an existing error:\n".$exception->__toString());
- header('HTTP/1.0 500 Internal Server Error', true, 500);
- }
- $this->getApplication()->getResponse()->flush();
- }
-
- /**
- * @param Exception exception details.
- * @return array exception stack trace details.
- */
- private function getExceptionStackTrace($exception)
- {
- $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
- $data['file']=$exception->getFile();
- $data['line']=$exception->getLine();
- $data['trace']=$exception->getTrace();
- if($exception instanceof TPhpErrorException)
- {
- // if PHP exception, we want to show the 2nd stack level context
- // because the 1st stack level is of little use (it's in error handler)
- if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
- {
- $data['file']=$trace[0]['file'];
- $data['line']=$trace[0]['line'];
- }
- }
- $data['type']=get_class($exception);
- $data['message']=$exception->getMessage();
- $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
- $data['time']=@strftime('%Y-%m-%d %H:%M',time());
- return $data;
- }
-}
-
-/**
- * TInvalidCallbackException class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInvalidCallbackException extends TException
-{
-}
-
+<?php +/** + * TActivePageAdapter, TCallbackErrorHandler and TInvalidCallbackException class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering) + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load callback response adapter class. + */ +Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter'); +Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript'); +Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter'); + +/** + * TActivePageAdapter class. + * + * Callback request handler. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering) + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActivePageAdapter extends TControlAdapter +{ + /** + * Callback response data header name. + */ + const CALLBACK_DATA_HEADER = 'X-PRADO-DATA'; + /** + * Callback response client-side action header name. + */ + const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS'; + /** + * Callback error header name. + */ + const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR'; + /** + * Callback page state header name. + */ + const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE'; + /** + * Script list header name. + */ + const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST'; + /** + * Stylesheet list header name. + */ + const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST'; + /** + * Hidden field list header name. + */ + const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST'; + + /** + * Callback redirect url header name. + */ + const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT'; + + /** + * @var ICallbackEventHandler callback event handler. + */ + private $_callbackEventTarget; + /** + * @var mixed callback event parameter. + */ + private $_callbackEventParameter; + /** + * @var TCallbackClientScript callback client script handler + */ + private $_callbackClient; + + private $_controlsToRender=array(); + + /** + * Constructor, trap errors and exception to let the callback response + * handle them. + */ + public function __construct(TPage $control) + { + parent::__construct($control); + + //TODO: can this be done later? + $response = $this->getApplication()->getResponse(); + $response->setAdapter(new TCallbackResponseAdapter($response)); + + $this->trapCallbackErrorsExceptions(); + } + + /** + * Process the callback request. + * @param THtmlWriter html content writer. + */ + public function processCallbackEvent($writer) + { + Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter'); + $this->raiseCallbackEvent(); + } + + /** + * Register a control for defered render() call. + * @param TControl control for defered rendering + * @param THtmlWriter the renderer + */ + public function registerControlToRender($control,$writer) + { + $id = $control->getUniqueID(); + if(!isset($this->_controlsToRender[$id])) + $this->_controlsToRender[$id] = array($control,$writer); + } + + /** + * Trap errors and exceptions to be handled by TCallbackErrorHandler. + */ + protected function trapCallbackErrorsExceptions() + { + $this->getApplication()->setErrorHandler(new TCallbackErrorHandler); + } + + /** + * Render the callback response. + * @param THtmlWriter html content writer. + */ + public function renderCallbackResponse($writer) + { + Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter'); + if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null) + $this->renderResponse($writer); + else + $this->redirect($url); + } + + /** + * Redirect url on the client-side using javascript. + * @param string new url to load. + */ + protected function redirect($url) + { + Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter'); + $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url); + //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url); + } + + /** + * Renders the callback response by adding additional callback data and + * javascript actions in the header and page state if required. + * @param THtmlWriter html content writer. + */ + protected function renderResponse($writer) + { + Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter'); + //renders all the defered render() calls. + foreach($this->_controlsToRender as $rid => $forRender) + $forRender[0]->render($forRender[1]); + + $response = $this->getResponse(); + + //send response data in header + if($response->getHasAdapter()) + { + $responseData = $response->getAdapter()->getResponseData(); + if($responseData!==null) + { + $data = TJavaScript::jsonEncode($responseData); + + $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data); + //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data); + } + } + + //sends page state in header + if(($handler = $this->getCallbackEventTarget()) !== null) + { + if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate()) + { + $pagestate = $this->getPage()->getClientState(); + $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate); + //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate); + } + } + + //safari must receive at least 1 byte of data. + $writer->write(" "); + + //output the end javascript + if($this->getPage()->getClientScript()->hasEndScripts()) + { + $writer = $response->createHtmlWriter(); + $this->getPage()->getClientScript()->renderEndScripts($writer); + $this->getPage()->getCallbackClient()->evaluateScript($writer); + } + + //output the actions + $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute(); + $actions = TJavaScript::jsonEncode($executeJavascript); + $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions); + //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions); + + + $cs = $this->Page->getClientScript(); + + // collect all stylesheet file references + $stylesheets = $cs->getStyleSheetUrls(); + if (count($stylesheets)>0) + $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets)); + + // collect all script file references + $scripts = $cs->getScriptUrls(); + if (count($scripts)>0) + $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts)); + + // collect all hidden field references + $fields = $cs->getHiddenFields(); + if (count($fields)>0) + $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields)); + } + + /** + * Appends data or javascript code to the body content surrounded with delimiters + */ + private function appendContentPart($response, $delimiter, $data) + { + $content = $response->createHtmlWriter(); + $content->getWriter()->setBoundary($delimiter); + $content->write($data); + } + + /** + * Trys to find the callback event handler and raise its callback event. + * @throws TInvalidCallbackException if call back target is not found. + * @throws TInvalidCallbackException if the requested target does not + * implement ICallbackEventHandler. + */ + private function raiseCallbackEvent() + { + if(($callbackHandler=$this->getCallbackEventTarget())!==null) + { + if($callbackHandler instanceof ICallbackEventHandler) + { + $param = $this->getCallbackEventParameter(); + $result = new TCallbackEventParameter($this->getResponse(), $param); + $callbackHandler->raiseCallbackEvent($result); + } + else + { + throw new TInvalidCallbackException( + 'callback_invalid_handler', $callbackHandler->getUniqueID()); + } + } + else + { + $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET); + throw new TInvalidCallbackException('callback_invalid_target', $target); + } + } + + /** + * @return TControl the control responsible for the current callback event, + * null if nonexistent + */ + public function getCallbackEventTarget() + { + if($this->_callbackEventTarget===null) + { + $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET); + if(!empty($eventTarget)) + $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget); + } + return $this->_callbackEventTarget; + } + + /** + * 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->_callbackEventTarget=$control; + } + + /** + * Gets callback parameter. JSON encoding is assumed. + * @return string postback event parameter + */ + public function getCallbackEventParameter() + { + if($this->_callbackEventParameter===null) + { + $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER); + if(strlen($param) > 0) + $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param); + } + return $this->_callbackEventParameter; + } + + /** + * @param mixed postback event parameter + */ + public function setCallbackEventParameter($value) + { + $this->_callbackEventParameter=$value; + } + + /** + * Gets the callback client script handler. It handlers the javascript functions + * to be executed during the callback response. + * @return TCallbackClientScript callback client handler. + */ + public function getCallbackClientHandler() + { + if($this->_callbackClient===null) + $this->_callbackClient = new TCallbackClientScript; + return $this->_callbackClient; + } +} + +/** + * TCallbackErrorHandler class. + * + * Captures errors and exceptions and send them back during callback response. + * When the application is in debug mode, the error and exception stack trace + * are shown. A TJavascriptLogger must be present on the client-side to view + * the error stack trace. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackErrorHandler extends TErrorHandler +{ + /** + * Displays the exceptions to the client-side TJavascriptLogger. + * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded. + * @param Exception exception details. + */ + protected function displayException($exception) + { + if($this->getApplication()->getMode()===TApplication::STATE_DEBUG) + { + $response = $this->getApplication()->getResponse(); + $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception)); + $response->setStatusCode(500, 'Internal Server Error'); + $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace); + } + else + { + error_log("Error happened while processing an existing error:\n".$exception->__toString()); + header('HTTP/1.0 500 Internal Server Error', true, 500); + } + $this->getApplication()->getResponse()->flush(); + } + + /** + * @param Exception exception details. + * @return array exception stack trace details. + */ + private function getExceptionStackTrace($exception) + { + $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500; + $data['file']=$exception->getFile(); + $data['line']=$exception->getLine(); + $data['trace']=$exception->getTrace(); + if($exception instanceof TPhpErrorException) + { + // if PHP exception, we want to show the 2nd stack level context + // because the 1st stack level is of little use (it's in error handler) + if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line'])) + { + $data['file']=$trace[0]['file']; + $data['line']=$trace[0]['line']; + } + } + $data['type']=get_class($exception); + $data['message']=$exception->getMessage(); + $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion(); + $data['time']=@strftime('%Y-%m-%d %H:%M',time()); + return $data; + } +} + +/** + * TInvalidCallbackException class. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TInvalidCallbackException extends TException +{ +} + diff --git a/framework/Web/UI/ActiveControls/TActivePanel.php b/framework/Web/UI/ActiveControls/TActivePanel.php index ae1dd09f..1edfa57c 100644 --- a/framework/Web/UI/ActiveControls/TActivePanel.php +++ b/framework/Web/UI/ActiveControls/TActivePanel.php @@ -1,100 +1,100 @@ -<?php
-/**
- * TActivePanel file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActivePanel is the TPanel active control counterpart.
- *
- * TActivePanel allows the client-side panel contents to be updated during a
- * callback response using the {@link render} method.
- *
- * Example: Assume $param is an instance of TCallbackEventParameter attached to
- * the OnCallback event of a TCallback with ID "callback1", and
- * "panel1" is the ID of a TActivePanel.
- * <code>
- * function callback1_requested($sender, $param)
- * {
- * $this->panel1->render($param->getNewWriter());
- * }
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePanel extends TPanel implements IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveControl standard active control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * Adds attribute id to the renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer) {
- $writer->addAttribute('id',$this->getClientID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders and replaces the panel's content on the client-side.
- * When render() is called before the OnPreRender event, such as when render()
- * is called during a callback event handler, the rendering
- * is defered until OnPreRender event is raised.
- * @param THtmlWriter html writer
- */
- public function render($writer)
- {
- if($this->getHasPreRendered())
- {
- parent::render($writer);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
- }
- else
- {
- $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
- if ($this->getHasControls())
- {
- // If we update a TActivePanel on callback,
- // We shouldn't update all childs, because the whole content will be replaced by
- // the parent
- foreach ($this->findControlsByType('IActiveControl', false) as $control)
- {
- $control->getActiveControl()->setEnableUpdate(false);
- }
- }
- }
- }
-}
-
+<?php +/** + * TActivePanel file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActivePanel is the TPanel active control counterpart. + * + * TActivePanel allows the client-side panel contents to be updated during a + * callback response using the {@link render} method. + * + * Example: Assume $param is an instance of TCallbackEventParameter attached to + * the OnCallback event of a TCallback with ID "callback1", and + * "panel1" is the ID of a TActivePanel. + * <code> + * function callback1_requested($sender, $param) + * { + * $this->panel1->render($param->getNewWriter()); + * } + * </code> + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActivePanel extends TPanel implements IActiveControl +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, by calling this constructor. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveControl standard active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Adds attribute id to the renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) { + $writer->addAttribute('id',$this->getClientID()); + parent::addAttributesToRender($writer); + } + + /** + * Renders and replaces the panel's content on the client-side. + * When render() is called before the OnPreRender event, such as when render() + * is called during a callback event handler, the rendering + * is defered until OnPreRender event is raised. + * @param THtmlWriter html writer + */ + public function render($writer) + { + if($this->getHasPreRendered()) + { + parent::render($writer); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->replaceContent($this,$writer); + } + else + { + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + if ($this->getHasControls()) + { + // If we update a TActivePanel on callback, + // We shouldn't update all childs, because the whole content will be replaced by + // the parent + foreach ($this->findControlsByType('IActiveControl', false) as $control) + { + $control->getActiveControl()->setEnableUpdate(false); + } + } + } + } +} + diff --git a/framework/Web/UI/ActiveControls/TActiveRatingList.php b/framework/Web/UI/ActiveControls/TActiveRatingList.php index 7c878dd8..81f50dd1 100644 --- a/framework/Web/UI/ActiveControls/TActiveRatingList.php +++ b/framework/Web/UI/ActiveControls/TActiveRatingList.php @@ -1,133 +1,133 @@ -<?php
-/**
- * TActiveRatingList class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveRatingList Class
- *
- * Displays clickable images that represent a TRadioButtonList
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveListControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- $this->setAdapter(new TActiveListControlAdapter($this));
- $this->setAutoPostBack(true);
- parent::__construct();
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- parent::setReadOnly($value);
- $value = $this->getReadOnly();
- $this->callClientFunction('setReadOnly',$value);
- }
-
- /**
- * @param float rating value, also sets the selected Index
- */
- public function setRating($value)
- {
- parent::setRating($value);
- $value = $this->getRating();
- $this->callClientFunction('setRating',$value);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $code = parent::getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
- }
-
- /**
- * @param string caption text
- */
- public function setCaption($value)
- {
- parent::setCaption($value);
- // if it's an active control, this should not be needed.
- $this->callClientFunction('setCaption',$value);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveRatingList';
- }
-}
-
+<?php +/** + * TActiveRatingList class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveRatingList Class + * + * Displays clickable images that represent a TRadioButtonList + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveListControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, by calling this constructor. + */ + public function __construct() + { + $this->setAdapter(new TActiveListControlAdapter($this)); + $this->setAutoPostBack(true); + parent::__construct(); + } + + /** + * @return TBaseActiveCallbackControl standard callback control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Raises the callback event. This method is required by {@link + * ICallbackEventHandler} interface. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $this->onCallback($param); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + parent::setReadOnly($value); + $value = $this->getReadOnly(); + $this->callClientFunction('setReadOnly',$value); + } + + /** + * @param float rating value, also sets the selected Index + */ + public function setRating($value) + { + parent::setRating($value); + $value = $this->getRating(); + $this->callClientFunction('setRating',$value); + } + + /** + * Calls the client-side static method for this control class. + * @param string static method name + * @param mixed method parmaeter + */ + protected function callClientFunction($func,$value) + { + if($this->getActiveControl()->canUpdateClientSide()) + { + $client = $this->getPage()->getCallbackClient(); + $code = parent::getClientClassName().'.'.$func; + $client->callClientFunction($code,array($this,$value)); + } + } + + /** + * @param string caption text + */ + public function setCaption($value) + { + parent::setCaption($value); + // if it's an active control, this should not be needed. + $this->callClientFunction('setCaption',$value); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveRatingList'; + } +} + diff --git a/framework/Web/UI/ActiveControls/TActiveTextBox.php b/framework/Web/UI/ActiveControls/TActiveTextBox.php index 1e2fc46f..562f59cd 100644 --- a/framework/Web/UI/ActiveControls/TActiveTextBox.php +++ b/framework/Web/UI/ActiveControls/TActiveTextBox.php @@ -1,125 +1,125 @@ -<?php
-/**
- * TActiveTextBox class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveTextBox class.
- *
- * TActiveTextBox allows the {@link setText Text} property of the textbox to
- * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
- * is true, changes to the textbox contents will perform a callback request causing
- * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
- * event.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client-side Text property can only be updated after the OnLoad stage.
- * @param string text content for the textbox
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
- $this->getPage()->getCallbackClient()->setValue($this, $value);
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveTextBox';
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-}
-
+<?php +/** + * TActiveTextBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveTextBox class. + * + * TActiveTextBox allows the {@link setText Text} property of the textbox to + * be changed during callback. When {@link setAutoPostBack AutoPostBack} property + * is true, changes to the textbox contents will perform a callback request causing + * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback} + * event. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, by calling this constructor. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveCallbackControl standard callback control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Client-side Text property can only be updated after the OnLoad stage. + * @param string text content for the textbox + */ + public function setText($value) + { + parent::setText($value); + if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData()) + $this->getPage()->getCallbackClient()->setValue($this, $value); + } + + /** + * Raises the callback event. This method is required by {@link + * ICallbackEventHandler} interface. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $this->onCallback($param); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveTextBox'; + } + + /** + * Override parent implementation, no javascript is rendered here instead + * the javascript required for active control is registered in {@link addAttributesToRender}. + */ + protected function renderClientControlScript($writer) + { + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } +} + diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php index 413d5c21..ce648b02 100644 --- a/framework/Web/UI/ActiveControls/TAutoComplete.php +++ b/framework/Web/UI/ActiveControls/TAutoComplete.php @@ -1,440 +1,440 @@ -<?php
-/**
- * TAutoComplete class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active text box.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TAutoComplete class.
- *
- * TAutoComplete is a textbox that provides a list of suggestion on
- * the current partial word typed in the textbox. The suggestions are
- * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
- * event. The events of the TActiveText (from which TAutoComplete is extended from)
- * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
- * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
- * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
- * vice versa.
- *
- * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
- * event handler. The partial word to match the suggestion is in the
- * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
- * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
- * method. This sets the datasource for the suggestions repeater, available through
- * the {@link getSuggestions Suggestions} property. Header, footer templates and
- * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
- * property and its sub-properties.
- *
- * The {@link setTextCssClass TextCssClass} property if set is used to find
- * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
- * that contains the actual text for the suggestion selected. That is,
- * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
- * will be used as suggestions.
- *
- * To return the list of suggestions back to the browser, supply a non-empty data source
- * and call databind. For example,
- * <code>
- * function autocomplete_suggestion($sender, $param)
- * {
- * $token = $param->getToken(); //the partial word to match
- * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
- * $sender->dataBind();
- * }
- * </code>
- *
- * The suggestion will be rendered when the {@link dataBind()} method is called
- * <strong>during a callback request</strong>.
- *
- * When an suggestion is selected, that is, when the use has clicked, pressed
- * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
- * event is raised. The
- * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
- * property contains the index of the selected suggestion.
- *
- * TAutoComplete allows multiple suggestions within one textbox with each
- * word or phrase separated by any characters specified in the
- * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
- * and {@link setMinChars MinChars} properties sets the delay and minimum number
- * of characters typed, respectively, before requesting for sugggestions.
- *
- * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
- * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
- *
- * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
- * are considered as text for the suggestion. Text within HTML elements with CSS class name
- * "informal" are ignored as text for suggestions.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoComplete extends TActiveTextBox implements INamingContainer
-{
- /**
- * @var ITemplate template for repeater items
- */
- private $_repeater=null;
- /**
- * @var TPanel result panel holding the suggestion items.
- */
- private $_resultPanel=null;
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function getSeparator()
- {
- return $this->getViewState('tokens', '');
- }
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function setSeparator($value)
- {
- $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
- }
-
- /**
- * @return float maximum delay (in seconds) before requesting a suggestion.
- */
- public function getFrequency()
- {
- return $this->getViewState('frequency', '');
- }
-
- /**
- * @param float maximum delay (in seconds) before requesting a suggestion.
- * Default is 0.4.
- */
- public function setFrequency($value)
- {
- $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
- }
-
- /**
- * @return integer minimum number of characters before requesting a suggestion.
- */
- public function getMinChars()
- {
- return $this->getViewState('minChars','');
- }
-
- /**
- * @param integer minimum number of characters before requesting a suggestion.
- */
- public function setMinChars($value)
- {
- $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
- }
-
- /**
- * @param string Css class name of the element to use for suggestion.
- */
- public function setTextCssClass($value)
- {
- $this->setViewState('TextCssClass', $value);
- }
-
- /**
- * @return string Css class name of the element to use for suggestion.
- */
- public function getTextCssClass()
- {
- return $this->getViewState('TextCssClass');
- }
-
- /**
- * Raises the callback event. This method is overrides the parent implementation.
- * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
- * {@link onTextChanged OnTextChanged} event event and then the
- * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
- * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
- * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $token = $param->getCallbackParameter();
- if(is_array($token) && count($token) == 2)
- {
- if($token[1] === '__TAutoComplete_onSuggest__')
- {
- $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
- $this->onSuggest($parameter);
- }
- else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
- {
- $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
- $this->onSuggestionSelected($parameter);
- }
- }
- else if($this->getAutoPostBack())
- parent::raiseCallbackEvent($param);
- }
-
- /**
- * This method is invoked when an autocomplete suggestion is requested.
- * The method raises 'OnSuggest' event. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onSuggest($param)
- {
- $this->raiseEvent('OnSuggest', $this, $param);
- }
-
- /**
- * This method is invoked when an autocomplete suggestion is selected.
- * The method raises 'OnSuggestionSelected' event. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onSuggestionSelected($param)
- {
- $this->raiseEvent('OnSuggestionSelected', $this, $param);
- }
-
- /**
- * @param array data source for suggestions.
- */
- public function setDataSource($data)
- {
- $this->getSuggestions()->setDataSource($data);
- }
-
- /**
- * Overrides parent implementation. Callback {@link renderSuggestions()} when
- * page's IsCallback property is true.
- */
- public function dataBind()
- {
- parent::dataBind();
- if($this->getPage()->getIsCallback())
- $this->renderSuggestions($this->getResponse()->createHtmlWriter());
- }
-
- /**
- * @return TPanel suggestion results panel.
- */
- public function getResultPanel()
- {
- if($this->_resultPanel===null)
- $this->_resultPanel = $this->createResultPanel();
- return $this->_resultPanel;
- }
-
- /**
- * @return TPanel new instance of result panel. Default uses TPanel.
- */
- protected function createResultPanel()
- {
- $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
- $this->getControls()->add($panel);
- $panel->setID('result');
- return $panel;
- }
-
- /**
- * @return TRepeater suggestion list repeater
- */
- public function getSuggestions()
- {
- if($this->_repeater===null)
- $this->_repeater = $this->createRepeater();
- return $this->_repeater;
- }
-
- /**
- * @return TRepeater new instance of TRepater to render the list of suggestions.
- */
- protected function createRepeater()
- {
- $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
- $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
- $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
- $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
- $this->getControls()->add($repeater);
- return $repeater;
- }
-
- /**
- * Renders the end tag and registers javascript effects library.
- */
- public function renderEndTag($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('effects');
- parent::renderEndTag($writer);
- $this->renderResultPanel($writer);
- }
-
- /**
- * Renders the result panel.
- * @param THtmlWriter the renderer.
- */
- protected function renderResultPanel($writer)
- {
- $this->getResultPanel()->render($writer);
- }
-
- /**
- * Renders the suggestions during a callback respones.
- * @param THtmlWriter the renderer.
- */
- public function renderCallback($writer)
- {
- $this->renderSuggestions($writer);
- }
-
- /**
- * Renders the suggestions repeater.
- * @param THtmlWriter the renderer.
- */
- public function renderSuggestions($writer)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $this->getSuggestions()->render($writer);
- $boundary = $writer->getWriter()->getBoundary();
- $this->getResponse()->getAdapter()->setResponseData($boundary);
- }
- }
-
- /**
- * @return array list of callback options.
- */
- protected function getPostBackOptions()
- {
- //disallow page state update ?
- //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
- $options = array();
- if(strlen($string = $this->getSeparator()))
- {
- $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
- $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
- $options['tokens'] = $token;
- }
- if($this->getAutoPostBack())
- {
- $options = array_merge($options,parent::getPostBackOptions());
- $options['AutoPostBack'] = true;
- }
- if(strlen($select = $this->getTextCssClass()))
- $options['select'] = $select;
- $options['ResultPanel'] = $this->getResultPanel()->getClientID();
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- if(($minchars=$this->getMinChars())!=='')
- $options['minChars'] = $minchars;
- if(($frequency=$this->getFrequency())!=='')
- $options['frequency'] = $frequency;
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- return $options;
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TAutoComplete';
- }
-}
-
-/**
- * TAutCompleteEventParameter contains the {@link getToken Token} requested by
- * the user for a partial match of the suggestions.
- *
- * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
- * suggestion selected by the user, -1 if not suggestion is selected.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteEventParameter extends TCallbackEventParameter
-{
- private $_selectedIndex=-1;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter, $index=-1)
- {
- parent::__construct($response, $parameter);
- $this->_selectedIndex=$index;
- }
-
- /**
- * @return int selected suggestion zero-based index, -1 if not selected.
- */
- public function getSelectedIndex()
- {
- return $this->_selectedIndex;
- }
-
- /**
- * @return string token for matching a list of suggestions.
- */
- public function getToken()
- {
- return $this->getCallbackParameter();
- }
-}
-
-/**
- * TAutoCompleteTemplate class.
- *
- * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
- * item template.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteTemplate extends TComponent implements ITemplate
-{
- private $_template;
-
- public function __construct($template)
- {
- $this->_template = $template;
- }
- /**
- * Instantiates the template.
- * It creates a {@link TDataList} control.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $parent->getControls()->add($this->_template);
- }
-}
-
+<?php +/** + * TAutoComplete class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active text box. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); +Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter'); + +/** + * TAutoComplete class. + * + * TAutoComplete is a textbox that provides a list of suggestion on + * the current partial word typed in the textbox. The suggestions are + * requested using callbacks, and raises the {@link onSuggestion OnSuggestion} + * event. The events of the TActiveText (from which TAutoComplete is extended from) + * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is, + * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} + * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and + * vice versa. + * + * The list of suggestions should be set in the {@link onSuggestion OnSuggestion} + * event handler. The partial word to match the suggestion is in the + * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter} + * property. The datasource of the TAutoComplete must be set using {@link setDataSource} + * method. This sets the datasource for the suggestions repeater, available through + * the {@link getSuggestions Suggestions} property. Header, footer templates and + * other properties of the repeater can be access via the {@link getSuggestions Suggestions} + * property and its sub-properties. + * + * The {@link setTextCssClass TextCssClass} property if set is used to find + * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate + * that contains the actual text for the suggestion selected. That is, + * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass} + * will be used as suggestions. + * + * To return the list of suggestions back to the browser, supply a non-empty data source + * and call databind. For example, + * <code> + * function autocomplete_suggestion($sender, $param) + * { + * $token = $param->getToken(); //the partial word to match + * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions + * $sender->dataBind(); + * } + * </code> + * + * The suggestion will be rendered when the {@link dataBind()} method is called + * <strong>during a callback request</strong>. + * + * When an suggestion is selected, that is, when the use has clicked, pressed + * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected} + * event is raised. The + * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter} + * property contains the index of the selected suggestion. + * + * TAutoComplete allows multiple suggestions within one textbox with each + * word or phrase separated by any characters specified in the + * {@link setSeparator Separator} property. The {@link setFrequency Frequency} + * and {@link setMinChars MinChars} properties sets the delay and minimum number + * of characters typed, respectively, before requesting for sugggestions. + * + * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events + * to handle post backs due to {@link setAutoPostBack AutoPostBack}. + * + * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements + * are considered as text for the suggestion. Text within HTML elements with CSS class name + * "informal" are ignored as text for suggestions. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TAutoComplete extends TActiveTextBox implements INamingContainer +{ + /** + * @var ITemplate template for repeater items + */ + private $_repeater=null; + /** + * @var TPanel result panel holding the suggestion items. + */ + private $_resultPanel=null; + + /** + * @return string word or token separators (delimiters). + */ + public function getSeparator() + { + return $this->getViewState('tokens', ''); + } + + /** + * @return string word or token separators (delimiters). + */ + public function setSeparator($value) + { + $this->setViewState('tokens', TPropertyValue::ensureString($value), ''); + } + + /** + * @return float maximum delay (in seconds) before requesting a suggestion. + */ + public function getFrequency() + { + return $this->getViewState('frequency', ''); + } + + /** + * @param float maximum delay (in seconds) before requesting a suggestion. + * Default is 0.4. + */ + public function setFrequency($value) + { + $this->setViewState('frequency', TPropertyValue::ensureFloat($value),''); + } + + /** + * @return integer minimum number of characters before requesting a suggestion. + */ + public function getMinChars() + { + return $this->getViewState('minChars',''); + } + + /** + * @param integer minimum number of characters before requesting a suggestion. + */ + public function setMinChars($value) + { + $this->setViewState('minChars', TPropertyValue::ensureInteger($value), ''); + } + + /** + * @param string Css class name of the element to use for suggestion. + */ + public function setTextCssClass($value) + { + $this->setViewState('TextCssClass', $value); + } + + /** + * @return string Css class name of the element to use for suggestion. + */ + public function getTextCssClass() + { + return $this->getViewState('TextCssClass'); + } + + /** + * Raises the callback event. This method is overrides the parent implementation. + * If {@link setAutoPostBack AutoPostBack} is enabled it will raise + * {@link onTextChanged OnTextChanged} event event and then the + * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is + * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged} + * and {@link onCallback OnCallback} events are <b>NOT</b> raised. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $token = $param->getCallbackParameter(); + if(is_array($token) && count($token) == 2) + { + if($token[1] === '__TAutoComplete_onSuggest__') + { + $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]); + $this->onSuggest($parameter); + } + else if($token[1] === '__TAutoComplete_onSuggestionSelected__') + { + $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]); + $this->onSuggestionSelected($parameter); + } + } + else if($this->getAutoPostBack()) + parent::raiseCallbackEvent($param); + } + + /** + * This method is invoked when an autocomplete suggestion is requested. + * The method raises 'OnSuggest' event. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onSuggest($param) + { + $this->raiseEvent('OnSuggest', $this, $param); + } + + /** + * This method is invoked when an autocomplete suggestion is selected. + * The method raises 'OnSuggestionSelected' event. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onSuggestionSelected($param) + { + $this->raiseEvent('OnSuggestionSelected', $this, $param); + } + + /** + * @param array data source for suggestions. + */ + public function setDataSource($data) + { + $this->getSuggestions()->setDataSource($data); + } + + /** + * Overrides parent implementation. Callback {@link renderSuggestions()} when + * page's IsCallback property is true. + */ + public function dataBind() + { + parent::dataBind(); + if($this->getPage()->getIsCallback()) + $this->renderSuggestions($this->getResponse()->createHtmlWriter()); + } + + /** + * @return TPanel suggestion results panel. + */ + public function getResultPanel() + { + if($this->_resultPanel===null) + $this->_resultPanel = $this->createResultPanel(); + return $this->_resultPanel; + } + + /** + * @return TPanel new instance of result panel. Default uses TPanel. + */ + protected function createResultPanel() + { + $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel'); + $this->getControls()->add($panel); + $panel->setID('result'); + return $panel; + } + + /** + * @return TRepeater suggestion list repeater + */ + public function getSuggestions() + { + if($this->_repeater===null) + $this->_repeater = $this->createRepeater(); + return $this->_repeater; + } + + /** + * @return TRepeater new instance of TRepater to render the list of suggestions. + */ + protected function createRepeater() + { + $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater'); + $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>')); + $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>')); + $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null)); + $this->getControls()->add($repeater); + return $repeater; + } + + /** + * Renders the end tag and registers javascript effects library. + */ + public function renderEndTag($writer) + { + $this->getPage()->getClientScript()->registerPradoScript('effects'); + parent::renderEndTag($writer); + $this->renderResultPanel($writer); + } + + /** + * Renders the result panel. + * @param THtmlWriter the renderer. + */ + protected function renderResultPanel($writer) + { + $this->getResultPanel()->render($writer); + } + + /** + * Renders the suggestions during a callback respones. + * @param THtmlWriter the renderer. + */ + public function renderCallback($writer) + { + $this->renderSuggestions($writer); + } + + /** + * Renders the suggestions repeater. + * @param THtmlWriter the renderer. + */ + public function renderSuggestions($writer) + { + if($this->getActiveControl()->canUpdateClientSide()) + { + $this->getSuggestions()->render($writer); + $boundary = $writer->getWriter()->getBoundary(); + $this->getResponse()->getAdapter()->setResponseData($boundary); + } + } + + /** + * @return array list of callback options. + */ + protected function getPostBackOptions() + { + //disallow page state update ? + //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false); + $options = array(); + if(strlen($string = $this->getSeparator())) + { + $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r")); + $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY); + $options['tokens'] = $token; + } + if($this->getAutoPostBack()) + { + $options = array_merge($options,parent::getPostBackOptions()); + $options['AutoPostBack'] = true; + } + if(strlen($select = $this->getTextCssClass())) + $options['select'] = $select; + $options['ResultPanel'] = $this->getResultPanel()->getClientID(); + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + if(($minchars=$this->getMinChars())!=='') + $options['minChars'] = $minchars; + if(($frequency=$this->getFrequency())!=='') + $options['frequency'] = $frequency; + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + return $options; + } + + /** + * Override parent implementation, no javascript is rendered here instead + * the javascript required for active control is registered in {@link addAttributesToRender}. + */ + protected function renderClientControlScript($writer) + { + } + + /** + * @return string corresponding javascript class name for this TActiveButton. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TAutoComplete'; + } +} + +/** + * TAutCompleteEventParameter contains the {@link getToken Token} requested by + * the user for a partial match of the suggestions. + * + * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the + * suggestion selected by the user, -1 if not suggestion is selected. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TAutoCompleteEventParameter extends TCallbackEventParameter +{ + private $_selectedIndex=-1; + + /** + * Creates a new TCallbackEventParameter. + */ + public function __construct($response, $parameter, $index=-1) + { + parent::__construct($response, $parameter); + $this->_selectedIndex=$index; + } + + /** + * @return int selected suggestion zero-based index, -1 if not selected. + */ + public function getSelectedIndex() + { + return $this->_selectedIndex; + } + + /** + * @return string token for matching a list of suggestions. + */ + public function getToken() + { + return $this->getCallbackParameter(); + } +} + +/** + * TAutoCompleteTemplate class. + * + * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate + * item template. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TAutoCompleteTemplate extends TComponent implements ITemplate +{ + private $_template; + + public function __construct($template) + { + $this->_template = $template; + } + /** + * Instantiates the template. + * It creates a {@link TDataList} control. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $parent->getControls()->add($this->_template); + } +} + diff --git a/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/framework/Web/UI/ActiveControls/TBaseActiveControl.php index d3391b71..c412a2e2 100644 --- a/framework/Web/UI/ActiveControls/TBaseActiveControl.php +++ b/framework/Web/UI/ActiveControls/TBaseActiveControl.php @@ -1,392 +1,392 @@ -<?php
-/**
- * TBaseActiveControl and TBaseActiveCallbackControl class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TBaseActiveControl class provided additional basic property for every
- * active control. An instance of TBaseActiveControl or its decendent
- * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
- * method.
- *
- * The {@link setEnableUpdate EnableUpdate} property determines wether the active
- * control is allowed to update the contents of the client-side when the callback
- * response returns.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveControl extends TComponent
-{
- /**
- * @var TMap map of active control options.
- */
- private $_options;
- /**
- * @var TControl attached control.
- */
- private $_control;
-
- /**
- * Constructor. Attach a base active control to an active control instance.
- * @param TControl active control
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_options = new TMap;
- }
-
- /**
- * Sets a named options with a value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed new value.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function setOption($name,$value,$default=null)
- {
- $value = ($value===null) ? $default : $value;
- if($value!==null)
- $this->_options->add($name,$value);
- }
-
- /**
- * Gets an option named value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function getOption($name,$default=null)
- {
- $item = $this->_options->itemAt($name);
- return ($item===null) ? $default : $item;
- }
-
- /**
- * @return TMap active control options
- */
- protected function getOptions()
- {
- return $this->_options;
- }
-
- /**
- * @return TPage the page containing the attached control.
- */
- protected function getPage()
- {
- return $this->_control->getPage();
- }
-
- /**
- * @return TControl the attached control.
- */
- protected function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @param boolean true to allow fine grain callback updates.
- */
- public function setEnableUpdate($value)
- {
- $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true to allow fine grain callback updates.
- */
- public function getEnableUpdate()
- {
- return $this->getOption('EnableUpdate', true);
- }
-
- /**
- * Returns true if callback response is allowed to update the browser contents.
- * Is is true if the control is initilized, and is a callback request and
- * the {@link setEnableUpdate EnableUpdate} property is true and
- * the page is not loading post data.
- * @return boolean true if the callback response is allowed update
- * client-side contents.
- */
- public function canUpdateClientSide($bDontRequireVisibility=false)
- {
- return $this->getControl()->getHasChildInitialized()
- && $this->getPage()->getIsLoadingPostData() == false
- && $this->getPage()->getIsCallback()
- && $this->getEnableUpdate()
- && ($bDontRequireVisibility || $this->getControl()->getVisible());
- }
-}
-
-/**
- * TBaseActiveCallbackControl is a common set of options and functionality for
- * active controls that can perform callback requests.
- *
- * The properties of TBaseActiveCallbackControl can be accessed and changed from
- * each individual active controls' {@link getActiveControl ActiveControl}
- * property.
- *
- * The following example sets the validation group property of a TCallback component.
- * <code>
- * <com:TCallback ActiveControl.ValidationGroup="group1" ... />
- * </code>
- *
- * Additional client-side options and events can be set using the
- * {@link getClientSide ClientSide} property. The following example shows
- * an alert box when a TCallback component response returns successfully.
- * <code>
- * <com:TCallback ActiveControl.ClientSide.OnSuccess="alert('ok!')" ... />
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveCallbackControl extends TBaseActiveControl
-{
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g. <com:TCallback ActiveControl.ClientSide.OnSuccess="..." />
- * See {@link TCallbackClientSide} for details on the properties of ClientSide.
- * @return TCallbackClientSide client-side callback options.
- */
- public function getClientSide()
- {
- if(($client = $this->getOption('ClientSide'))===null)
- {
- $client = $this->createClientSide();
- $this->setOption('ClientSide', $client);
- }
- return $client;
- }
-
- /**
- * Sets the client side options. Can only be set when client side is null.
- * @param TCallbackClientSide client side options.
- */
- public function setClientSide($client)
- {
- if( $this->getOption('ClientSide')===null)
- $this->setOption('ClientSide', $client);
- else
- throw new TConfigurationException(
- 'active_controls_client_side_exists', $this->getControl()->getID());
- }
-
- /**
- * @return TCallbackClientSide callback client-side options.
- */
- protected function createClientSide()
- {
- return new TCallbackClientSide;
- }
-
- /**
- * Sets default callback options. Takes the ID of a TCallbackOptions
- * component to duplicate the client-side
- * options for this control. The {@link getClientSide ClientSide}
- * subproperties takes precedence over the CallbackOptions property.
- * @param string ID of a TCallbackOptions control from which ClientSide
- * options are cloned.
- */
- public function setCallbackOptions($value)
- {
- $this->setOption('CallbackOptions', $value, '');
- }
-
- /**
- * @return string ID of a TCallbackOptions control from which ClientSide
- * options are duplicated.
- */
- public function getCallbackOptions()
- {
- return $this->getOption('CallbackOptions', '');
- }
-
- /**
- * Returns an array of default callback client-side options. The default options
- * are obtained from the client-side options of a TCallbackOptions control with
- * ID specified by {@link setCallbackOptions CallbackOptions}.
- * @return array list of default callback client-side options.
- */
- protected function getDefaultClientSideOptions()
- {
- if(($id=$this->getCallbackOptions())!=='')
- {
- if(($pos=strrpos($id,'.'))!==false)
- {
- $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
- $newid=substr($id,$pos+1);
- if ($control!==null)
- $control=$control->$newid;
- }
- else
- {
- $control=$this->getControl()->findControl($id);
- }
-
- if($control instanceof TCallbackOptions)
- return $control->getClientSide()->getOptions()->toArray();
- else
- throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
- }
-
- return array();
- }
-
- /**
- * @return boolean whether callback event trigger by this button will cause
- * input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getOption('CausesValidation',true);
- }
-
- /**
- * @param boolean whether callback event trigger by this button will cause
- * input validation
- */
- public function setCausesValidation($value)
- {
- $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation
- * upon callback
- */
- public function getValidationGroup()
- {
- return $this->getOption('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation
- * upon callback
- */
- public function setValidationGroup($value)
- {
- $this->setOption('ValidationGroup',$value,'');
- }
-
- /**
- * @return boolean whether to perform validation if the callback is
- * requested.
- */
- public function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param mixed callback parameter value.
- */
- public function setCallbackParameter($value)
- {
- $this->setOption('CallbackParameter', $value, '');
- }
-
- /**
- * @return mixed callback parameter value.
- */
- public function getCallbackParameter()
- {
- return $this->getOption('CallbackParameter', '');
- }
-
-
- /**
- * @return array list of callback javascript options.
- */
- protected function getClientSideOptions()
- {
- $default = $this->getDefaultClientSideOptions();
- $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
- $validate = $this->getCausesValidation();
- $options['CausesValidation']= $validate ? '' : false;
- $options['ValidationGroup']=$this->getValidationGroup();
- $options['CallbackParameter'] = $this->getCallbackParameter();
- return $options;
- }
-
- /**
- * Registers the callback control javascript code. Client-side options are
- * merged and passed to the javascript code. This method should be called by
- * Active component developers wanting to register the javascript to initialize
- * the active component with additional options offered by the
- * {@link getClientSide ClientSide} property.
- * @param string client side javascript class name.
- * @param array additional callback options.
- */
- public function registerCallbackClientScript($class,$options=null)
- {
- $cs = $this->getPage()->getClientScript();
- if(is_array($options))
- $options = array_merge($this->getClientSideOptions(),$options);
- else
- $options = $this->getClientSideOptions();
-
- //remove true as default to save bytes
- if($options['CausesValidation']===true)
- $options['CausesValidation']='';
- $cs->registerCallbackControl($class, $options);
- }
-
- /**
- * Returns the javascript callback request instance. To invoke a callback
- * request for this control call the <tt>dispatch()</tt> method on the
- * request instance. Example code in javascript
- * <code>
- * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
- * request.setParameter('hello');
- * request.dispatch(); //make the callback request.
- * </code>
- *
- * Alternatively,
- * <code>
- * //dispatches immediately
- * Prado.Callback("<%= $this->mycallback->UniqueID %>",
- * $this->mycallback->ActiveControl->JsCallbackOptions);
- * </code>
- * @return string javascript client-side callback request object (javascript
- * code)
- */
- public function getJavascript()
- {
- $client = $this->getPage()->getClientScript();
- return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions());
- }
-
- /**
- * @param string callback requestion options as javascript code.
- */
- public function getJsCallbackOptions()
- {
- return TJavaScript::encode($this->getClientSideOptions());
- }
-}
-
+<?php +/** + * TBaseActiveControl and TBaseActiveCallbackControl class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide'); + +/** + * TBaseActiveControl class provided additional basic property for every + * active control. An instance of TBaseActiveControl or its decendent + * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()} + * method. + * + * The {@link setEnableUpdate EnableUpdate} property determines wether the active + * control is allowed to update the contents of the client-side when the callback + * response returns. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TBaseActiveControl extends TComponent +{ + /** + * @var TMap map of active control options. + */ + private $_options; + /** + * @var TControl attached control. + */ + private $_control; + + /** + * Constructor. Attach a base active control to an active control instance. + * @param TControl active control + */ + public function __construct($control) + { + $this->_control = $control; + $this->_options = new TMap; + } + + /** + * Sets a named options with a value. Options are used to store and retrive + * named values for the base active controls. + * @param string option name. + * @param mixed new value. + * @param mixed default value. + * @return mixed options value. + */ + protected function setOption($name,$value,$default=null) + { + $value = ($value===null) ? $default : $value; + if($value!==null) + $this->_options->add($name,$value); + } + + /** + * Gets an option named value. Options are used to store and retrive + * named values for the base active controls. + * @param string option name. + * @param mixed default value. + * @return mixed options value. + */ + protected function getOption($name,$default=null) + { + $item = $this->_options->itemAt($name); + return ($item===null) ? $default : $item; + } + + /** + * @return TMap active control options + */ + protected function getOptions() + { + return $this->_options; + } + + /** + * @return TPage the page containing the attached control. + */ + protected function getPage() + { + return $this->_control->getPage(); + } + + /** + * @return TControl the attached control. + */ + protected function getControl() + { + return $this->_control; + } + + /** + * @param boolean true to allow fine grain callback updates. + */ + public function setEnableUpdate($value) + { + $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return boolean true to allow fine grain callback updates. + */ + public function getEnableUpdate() + { + return $this->getOption('EnableUpdate', true); + } + + /** + * Returns true if callback response is allowed to update the browser contents. + * Is is true if the control is initilized, and is a callback request and + * the {@link setEnableUpdate EnableUpdate} property is true and + * the page is not loading post data. + * @return boolean true if the callback response is allowed update + * client-side contents. + */ + public function canUpdateClientSide($bDontRequireVisibility=false) + { + return $this->getControl()->getHasChildInitialized() + && $this->getPage()->getIsLoadingPostData() == false + && $this->getPage()->getIsCallback() + && $this->getEnableUpdate() + && ($bDontRequireVisibility || $this->getControl()->getVisible()); + } +} + +/** + * TBaseActiveCallbackControl is a common set of options and functionality for + * active controls that can perform callback requests. + * + * The properties of TBaseActiveCallbackControl can be accessed and changed from + * each individual active controls' {@link getActiveControl ActiveControl} + * property. + * + * The following example sets the validation group property of a TCallback component. + * <code> + * <com:TCallback ActiveControl.ValidationGroup="group1" ... /> + * </code> + * + * Additional client-side options and events can be set using the + * {@link getClientSide ClientSide} property. The following example shows + * an alert box when a TCallback component response returns successfully. + * <code> + * <com:TCallback ActiveControl.ClientSide.OnSuccess="alert('ok!')" ... /> + * </code> + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TBaseActiveCallbackControl extends TBaseActiveControl +{ + /** + * Callback client-side options can be set by setting the properties of + * the ClientSide property. E.g. <com:TCallback ActiveControl.ClientSide.OnSuccess="..." /> + * See {@link TCallbackClientSide} for details on the properties of ClientSide. + * @return TCallbackClientSide client-side callback options. + */ + public function getClientSide() + { + if(($client = $this->getOption('ClientSide'))===null) + { + $client = $this->createClientSide(); + $this->setOption('ClientSide', $client); + } + return $client; + } + + /** + * Sets the client side options. Can only be set when client side is null. + * @param TCallbackClientSide client side options. + */ + public function setClientSide($client) + { + if( $this->getOption('ClientSide')===null) + $this->setOption('ClientSide', $client); + else + throw new TConfigurationException( + 'active_controls_client_side_exists', $this->getControl()->getID()); + } + + /** + * @return TCallbackClientSide callback client-side options. + */ + protected function createClientSide() + { + return new TCallbackClientSide; + } + + /** + * Sets default callback options. Takes the ID of a TCallbackOptions + * component to duplicate the client-side + * options for this control. The {@link getClientSide ClientSide} + * subproperties takes precedence over the CallbackOptions property. + * @param string ID of a TCallbackOptions control from which ClientSide + * options are cloned. + */ + public function setCallbackOptions($value) + { + $this->setOption('CallbackOptions', $value, ''); + } + + /** + * @return string ID of a TCallbackOptions control from which ClientSide + * options are duplicated. + */ + public function getCallbackOptions() + { + return $this->getOption('CallbackOptions', ''); + } + + /** + * Returns an array of default callback client-side options. The default options + * are obtained from the client-side options of a TCallbackOptions control with + * ID specified by {@link setCallbackOptions CallbackOptions}. + * @return array list of default callback client-side options. + */ + protected function getDefaultClientSideOptions() + { + if(($id=$this->getCallbackOptions())!=='') + { + if(($pos=strrpos($id,'.'))!==false) + { + $control=$this->getControl()->getSubProperty(substr($id,0,$pos)); + $newid=substr($id,$pos+1); + if ($control!==null) + $control=$control->$newid; + } + else + { + $control=$this->getControl()->findControl($id); + } + + if($control instanceof TCallbackOptions) + return $control->getClientSide()->getOptions()->toArray(); + else + throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id); + } + + return array(); + } + + /** + * @return boolean whether callback event trigger by this button will cause + * input validation, default is true + */ + public function getCausesValidation() + { + return $this->getOption('CausesValidation',true); + } + + /** + * @param boolean whether callback event trigger by this button will cause + * input validation + */ + public function setCausesValidation($value) + { + $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the button causes validation + * upon callback + */ + public function getValidationGroup() + { + return $this->getOption('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation + * upon callback + */ + public function setValidationGroup($value) + { + $this->setOption('ValidationGroup',$value,''); + } + + /** + * @return boolean whether to perform validation if the callback is + * requested. + */ + public function canCauseValidation() + { + if($this->getCausesValidation()) + { + $group=$this->getValidationGroup(); + return $this->getPage()->getValidators($group)->getCount()>0; + } + else + return false; + } + + /** + * @param mixed callback parameter value. + */ + public function setCallbackParameter($value) + { + $this->setOption('CallbackParameter', $value, ''); + } + + /** + * @return mixed callback parameter value. + */ + public function getCallbackParameter() + { + return $this->getOption('CallbackParameter', ''); + } + + + /** + * @return array list of callback javascript options. + */ + protected function getClientSideOptions() + { + $default = $this->getDefaultClientSideOptions(); + $options = array_merge($default,$this->getClientSide()->getOptions()->toArray()); + $validate = $this->getCausesValidation(); + $options['CausesValidation']= $validate ? '' : false; + $options['ValidationGroup']=$this->getValidationGroup(); + $options['CallbackParameter'] = $this->getCallbackParameter(); + return $options; + } + + /** + * Registers the callback control javascript code. Client-side options are + * merged and passed to the javascript code. This method should be called by + * Active component developers wanting to register the javascript to initialize + * the active component with additional options offered by the + * {@link getClientSide ClientSide} property. + * @param string client side javascript class name. + * @param array additional callback options. + */ + public function registerCallbackClientScript($class,$options=null) + { + $cs = $this->getPage()->getClientScript(); + if(is_array($options)) + $options = array_merge($this->getClientSideOptions(),$options); + else + $options = $this->getClientSideOptions(); + + //remove true as default to save bytes + if($options['CausesValidation']===true) + $options['CausesValidation']=''; + $cs->registerCallbackControl($class, $options); + } + + /** + * Returns the javascript callback request instance. To invoke a callback + * request for this control call the <tt>dispatch()</tt> method on the + * request instance. Example code in javascript + * <code> + * var request = <%= $this->mycallback->ActiveControl->Javascript %>; + * request.setParameter('hello'); + * request.dispatch(); //make the callback request. + * </code> + * + * Alternatively, + * <code> + * //dispatches immediately + * Prado.Callback("<%= $this->mycallback->UniqueID %>", + * $this->mycallback->ActiveControl->JsCallbackOptions); + * </code> + * @return string javascript client-side callback request object (javascript + * code) + */ + public function getJavascript() + { + $client = $this->getPage()->getClientScript(); + return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions()); + } + + /** + * @param string callback requestion options as javascript code. + */ + public function getJsCallbackOptions() + { + return TJavaScript::encode($this->getClientSideOptions()); + } +} + diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php index 7a1f54b7..662bc03f 100644 --- a/framework/Web/UI/ActiveControls/TCallback.php +++ b/framework/Web/UI/ActiveControls/TCallback.php @@ -1,101 +1,101 @@ -<?php
-/**
- * TCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TCallback component class.
- *
- * The TCallback provides a basic callback handler that can be invoked from the
- * client side by running the javascript code obtained from the
- * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
- * The event {@link onCallback OnCallback} is raised when a callback is requested made.
- *
- * Example usage:
- * <code>
- * <com:TCallback ID="callback1" OnCallback="callback1_Requested" />
- * <script type="text/javascript">
- * function do_callback1()
- * {
- * var request = <%= $this->callback1->ActiveControl->Javascript %>;
- * request.dispatch();
- * }
- * </script>
- * <div onclick="do_callback1()">Click Me!</div>
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, call this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
- * {@link getCausesValidation ActiveControl.CausesValidation} is true,
- * it will invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onCallback OnCallback} event. This method is mainly
- * used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- if($this->getActiveControl()->canCauseValidation())
- $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-}
-
+<?php +/** + * TCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TCallback component class. + * + * The TCallback provides a basic callback handler that can be invoked from the + * client side by running the javascript code obtained from the + * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property. + * The event {@link onCallback OnCallback} is raised when a callback is requested made. + * + * Example usage: + * <code> + * <com:TCallback ID="callback1" OnCallback="callback1_Requested" /> + * <script type="text/javascript"> + * function do_callback1() + * { + * var request = <%= $this->callback1->ActiveControl->Javascript %>; + * request.dispatch(); + * } + * </script> + * <div onclick="do_callback1()">Click Me!</div> + * </code> + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallback extends TControl implements ICallbackEventHandler, IActiveControl +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. If you override this class, be sure to set the + * adapter appropriately by, for example, call this constructor. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveCallbackControl standard callback options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Raises the callback event. This method is required by + * {@link ICallbackEventHandler ICallbackEventHandler} interface. If + * {@link getCausesValidation ActiveControl.CausesValidation} is true, + * it will invoke the page's {@link TPage::validate validate} method first. + * It will raise {@link onCallback OnCallback} event. This method is mainly + * used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + if($this->getActiveControl()->canCauseValidation()) + $this->getPage()->validate($this->getActiveControl()->getValidationGroup()); + $this->onCallback($param); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $this->raiseEvent('OnCallback', $this, $param); + } +} + diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php index 6dcbe3d0..291f22f2 100644 --- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php +++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php @@ -1,705 +1,705 @@ -<?php
-/**
- * TCallbackClientScript class file
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientScript class.
- *
- * The TCallbackClientScript class provides corresponding methods that can be
- * executed on the client-side (i.e. the browser client that is viewing
- * the page) during a callback response.
- *
- * The avaiable methods includes setting/clicking input elements, changing Css
- * styles, hiding/showing elements, and adding visual effects to elements on the
- * page. The client-side methods can be access through the CallbackClient
- * property available in TPage.
- *
- * For example, to hide "$myTextBox" element during callback response, do
- * <code>
- * $this->getPage()->getCallbackClient()->hide($myTextBox);
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientScript extends TApplicationComponent
-{
- /**
- * @var TList list of client functions to execute.
- */
- private $_actions;
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- $this->_actions = new TList;
- }
-
- /**
- * @return array list of client function to be executed during callback
- * response.
- */
- public function getClientFunctionsToExecute()
- {
- return $this->_actions->toArray();
- }
-
- /**
- * Executes a client-side statement.
- * @param string javascript function name
- * @param array list of arguments for the function
- */
- public function callClientFunction($function, $params=null)
- {
- if(!is_array($params))
- $params = array($params);
-
- if(count($params) > 0)
- {
- if($params[0] instanceof TControl)
- $params[0] = $params[0]->getClientID();
- }
- $this->_actions->add(array($function => $params));
- }
-
- /**
- * Client script to set the value of a particular input element.
- * @param TControl control element to set the new value
- * @param string new value
- */
- public function setValue($input, $text)
- {
- $this->callClientFunction('Prado.Element.setValue', array($input, $text));
- }
-
- /**
- * Client script to select/clear/check a drop down list, check box list,
- * or radio button list.
- * The second parameter determines the selection method. Valid methods are
- * - <b>Value</b>, select or check by value
- * - <b>Values</b>, select or check by a list of values
- * - <b>Index</b>, select or check by index (zero based index)
- * - <b>Indices</b>, select or check by a list of index (zero based index)
- * - <b>Clear</b>, clears or selections or checks in the list
- * - <b>All</b>, select all
- * - <b>Invert</b>, invert the selection.
- * @param TControl list control
- * @param string selection method
- * @param string|int the value or index to select/check.
- * @param string selection control type, either 'check' or 'select'
- */
- public function select($control, $method='Value', $value=null, $type=null)
- {
- $method = TPropertyValue::ensureEnum($method,
- 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
- $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
- $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
- $this->callClientFunction('Prado.Element.select',
- array($control, $type.$method, $value, $total));
- }
-
- private function getSelectionControlType($control)
- {
- if(is_string($control)) return 'check';
- if($control instanceof TCheckBoxList)
- return 'check';
- if($control instanceof TCheckBox)
- return 'check';
- return 'select';
- }
-
- private function getSelectionControlIsListType($control)
- {
- return $control instanceof TListControl;
- }
-
- /**
- * Client script to click on an element. <b>This client-side function is unpredictable.</b>
- *
- * @param TControl control element or element id
- */
- public function click($control)
- {
- $this->callClientFunction('Prado.Element.click', $control);
- }
-
- /**
- * Client script to check or uncheck a checkbox or radio button.
- * @param TControl control element or element id
- * @param boolean check or uncheck the checkbox or radio button.
- */
- public function check($checkbox, $checked=true)
- {
- $this->select($checkbox, "Value", $checked);
- }
-
- /**
- * Raise the client side event (given by $eventName) on a particular element.
- * @param TControl control element or element id
- * @param string Event name, e.g. "click"
- */
- public function raiseClientEvent($control, $eventName)
- {
- $this->callClientFunction('Event.fireEvent',
- array($control, strtolower($eventName)));
- }
-
- /**
- * Sets the attribute of a particular control.
- * @param TControl control element or element id
- * @param string attribute name
- * @param string attribute value
- */
- public function setAttribute($control, $name, $value)
- {
- // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
- if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
- $control=$control->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
- }
-
- /**
- * Sets the options of a select input element.
- * @param TControl control element or element id
- * @param TCollection a list of new options
- */
- public function setListItems($control, $items)
- {
- $options = array();
- if($control instanceof TListControl)
- {
- $promptText = $control->getPromptText();
- $promptValue = $control->getPromptValue();
-
- if($promptValue==='')
- $promptValue = $promptText;
-
- if($promptValue!=='')
- $options[] = array($promptText, $promptValue);
- }
-
- foreach($items as $item)
- {
- if($item->getHasAttributes())
- $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
- else
- $options[] = array($item->getText(),$item->getValue());
- }
- $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
- }
-
- /**
- * Shows an element by changing its CSS display style as empty.
- * @param TControl control element or element id
- */
- public function show($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.show', $element);
- }
-
- /**
- * Hides an element by changing its CSS display style to "none".
- * @param TControl control element or element id
- */
- public function hide($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.hide', $element);
- }
-
- /**
- * Toggles the visibility of the element.
- * @param TControl control element or element id
- * @param string visual effect, such as, 'appear' or 'slide' or 'blind'.
- * @param array additional options.
- */
- public function toggle($element, $effect=null, $options=array())
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.toggle', array($element,$effect,$options));
- }
-
- /**
- * Removes an element from the HTML page.
- * @param TControl control element or element id
- */
- public function remove($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.remove', $element);
- }
-
- public function addPostDataLoader($name)
- {
- $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name);
- }
-
- /**
- * Update the element's innerHTML with new content.
- * @param TControl control element or element id
- * @param TControl new HTML content, if content is of a TControl, the
- * controls render method is called.
- */
- public function update($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Element.update');
- }
-
- /**
- * Add a Css class name to the element.
- * @param TControl control element or element id
- * @param string CssClass name to add.
- */
- public function addCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.addClassName', array($element, $cssClass));
- }
-
- /**
- * Remove a Css class name from the element.
- * @param TControl control element or element id
- * @param string CssClass name to remove.
- */
- public function removeCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.removeClassName', array($element, $cssClass));
- }
-
- /**
- * Sets the CssClass of an element.
- * @param TControl control element or element id
- * @param string new CssClass name for the element.
- */
- /*public function setCssClass($element, $cssClass)
- {
- $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass));
- }*/
-
- /**
- * Scroll the top of the browser viewing area to the location of the
- * element.
- * @param TControl control element or element id
- */
- public function scrollTo($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.scrollTo', $element);
- }
-
- /**
- * Focus on a particular element.
- * @param TControl control element or element id.
- */
- public function focus($element)
- {
- $this->callClientFunction('Prado.Element.focus', $element);
- }
-
- /**
- * Sets the style of element. The style must be a key-value array where the
- * key is the style property and the value is the style value.
- * @param TControl control element or element id
- * @param array list of key-value pairs as style property and style value.
- */
- public function setStyle($element, $styles)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setStyle', array($element, $styles));
- }
-
- /**
- * Append a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function appendContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.append');
- }
-
- /**
- * Prepend a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function prependContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.prepend');
- }
-
- /**
- * Insert a HTML fragement after the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentAfter($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.after');
- }
-
- /**
- * Insert a HTML fragement in before the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentBefore($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.before');
- }
-
- /**
- * Replace the content of an element with new content. The new content can
- * be a string or a TControl component. If the <tt>content</tt> parameter is
- * a TControl component, its rendered method will be called and its contents
- * will be used for replacement.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- * @param string replacement method, default is to replace the outter
- * html content.
- * @param string provide a custom boundary.
- * @see insertAbout
- * @see insertBelow
- * @see insertBefore
- * @see insertAfter
- */
- protected function replace($element, $content, $method="Element.replace", $boundary=null)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- $content = null;
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- $content = null;
- }
-
- $this->callClientFunction('Prado.Element.replace',
- array($element, $method, $content, $boundary));
- }
-
- /**
- * Replace the content of an element with new content contained in writer.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- */
- public function replaceContent($element,$content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content);
- }
-
- /**
- * Evaluate a block of javascript enclosed in a boundary.
- * @param THtmlWriter writer for the content.
- */
- public function evaluateScript($writer)
- {
- $this->replace(null, $writer, 'Prado.Element.evaluateScript');
- }
-
- /**
- * Appends a block of inline javascript enclosed in a boundary.
- * Similar to to evaluateScript(), but functions declared in the
- * inline block will be available to page elements.
- * @param THtmlWriter writer for the content.
- */
- public function appendScriptBlock($content)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- }
-
- $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
- }
-
- /**
- * Renders the control and return the content boundary from
- * TCallbackResponseWriter. This method should only be used by framework
- * component developers. The render() method is defered to be called in the
- * TActivePageAdapter class.
- * @param TControl control to be rendered on callback response.
- * @return string the boundary for which the rendered content is wrapped.
- */
- private function getRenderedContentBoundary($control)
- {
- $writer = $this->getResponse()->createHtmlWriter();
- $adapter = $control->getPage()->getAdapter();
- $adapter->registerControlToRender($control, $writer);
- return $writer->getWriter()->getBoundary();
- }
-
- /**
- * @param THtmlWriter the writer responsible for rendering html content.
- * @return string content boundary.
- */
- private function getResponseContentBoundary($html)
- {
- if($html instanceof THtmlWriter)
- {
- if($html->getWriter() instanceof TCallbackResponseWriter)
- return $html->getWriter()->getBoundary();
- }
- return null;
- }
-
- /**
- * Add a visual effect the element.
- * @param string visual effect function name.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function visualEffect($type, $element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction($type, array($element, $options));
- }
-
- /**
- * Visual Effect: Gradually make the element appear.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function appear($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Appear', $element, $options);
- }
-
- /**
- * Visual Effect: Blind down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindDown', $element, $options);
- }
-
- /**
- * Visual Effect: Blind up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindUp', $element, $options);
-
- }
-
- /**
- * Visual Effect: Drop out.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function dropOut($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.DropOut', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fade($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fade', $element, $options);
- }
-
- /**
- * Visual Effect: Fold.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fold($element, $options = null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fold', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually make an element grow to a predetermined size.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function grow($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Grow', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually grow and fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function puff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Puff', $element, $options);
- }
-
- /**
- * Visual Effect: Pulsate.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function pulsate($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Pulsate', $element, $options);
- }
-
- /**
- * Visual Effect: Shake the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shake($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shake', $element, $options);
- }
-
- /**
- * Visual Effect: Shrink the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shrink($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shrink', $element, $options);
- }
-
- /**
- * Visual Effect: Slide down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideDown', $element, $options);
- }
-
- /**
- * Visual Effect: Side up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideUp', $element, $options);
- }
-
- /**
- * Visual Effect: Squish the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function squish($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Squish', $element, $options);
- }
-
- /**
- * Visual Effect: Switch Off effect.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function switchOff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SwitchOff', $element, $options);
- }
-
- /**
- * Visual Effect: High light the element for about 2 seconds.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function highlight($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Prado.Effect.Highlight', $element, $options);
- }
-
- /**
- * Set the opacity on a html element or control.
- * @param TControl control element or element id
- * @param float opacity value between 1 and 0
- */
- public function setOpacity($element, $value)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $value = TPropertyValue::ensureFloat($value);
- $this->callClientFunction('Element.setOpacity', array($element,$value));
- }
-}
-
+<?php +/** + * TCallbackClientScript class file + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackClientScript class. + * + * The TCallbackClientScript class provides corresponding methods that can be + * executed on the client-side (i.e. the browser client that is viewing + * the page) during a callback response. + * + * The avaiable methods includes setting/clicking input elements, changing Css + * styles, hiding/showing elements, and adding visual effects to elements on the + * page. The client-side methods can be access through the CallbackClient + * property available in TPage. + * + * For example, to hide "$myTextBox" element during callback response, do + * <code> + * $this->getPage()->getCallbackClient()->hide($myTextBox); + * </code> + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackClientScript extends TApplicationComponent +{ + /** + * @var TList list of client functions to execute. + */ + private $_actions; + + /** + * Constructor. + */ + public function __construct() + { + $this->_actions = new TList; + } + + /** + * @return array list of client function to be executed during callback + * response. + */ + public function getClientFunctionsToExecute() + { + return $this->_actions->toArray(); + } + + /** + * Executes a client-side statement. + * @param string javascript function name + * @param array list of arguments for the function + */ + public function callClientFunction($function, $params=null) + { + if(!is_array($params)) + $params = array($params); + + if(count($params) > 0) + { + if($params[0] instanceof TControl) + $params[0] = $params[0]->getClientID(); + } + $this->_actions->add(array($function => $params)); + } + + /** + * Client script to set the value of a particular input element. + * @param TControl control element to set the new value + * @param string new value + */ + public function setValue($input, $text) + { + $this->callClientFunction('Prado.Element.setValue', array($input, $text)); + } + + /** + * Client script to select/clear/check a drop down list, check box list, + * or radio button list. + * The second parameter determines the selection method. Valid methods are + * - <b>Value</b>, select or check by value + * - <b>Values</b>, select or check by a list of values + * - <b>Index</b>, select or check by index (zero based index) + * - <b>Indices</b>, select or check by a list of index (zero based index) + * - <b>Clear</b>, clears or selections or checks in the list + * - <b>All</b>, select all + * - <b>Invert</b>, invert the selection. + * @param TControl list control + * @param string selection method + * @param string|int the value or index to select/check. + * @param string selection control type, either 'check' or 'select' + */ + public function select($control, $method='Value', $value=null, $type=null) + { + $method = TPropertyValue::ensureEnum($method, + 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert'); + $type = ($type===null) ? $this->getSelectionControlType($control) : $type; + $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1; + $this->callClientFunction('Prado.Element.select', + array($control, $type.$method, $value, $total)); + } + + private function getSelectionControlType($control) + { + if(is_string($control)) return 'check'; + if($control instanceof TCheckBoxList) + return 'check'; + if($control instanceof TCheckBox) + return 'check'; + return 'select'; + } + + private function getSelectionControlIsListType($control) + { + return $control instanceof TListControl; + } + + /** + * Client script to click on an element. <b>This client-side function is unpredictable.</b> + * + * @param TControl control element or element id + */ + public function click($control) + { + $this->callClientFunction('Prado.Element.click', $control); + } + + /** + * Client script to check or uncheck a checkbox or radio button. + * @param TControl control element or element id + * @param boolean check or uncheck the checkbox or radio button. + */ + public function check($checkbox, $checked=true) + { + $this->select($checkbox, "Value", $checked); + } + + /** + * Raise the client side event (given by $eventName) on a particular element. + * @param TControl control element or element id + * @param string Event name, e.g. "click" + */ + public function raiseClientEvent($control, $eventName) + { + $this->callClientFunction('Event.fireEvent', + array($control, strtolower($eventName))); + } + + /** + * Sets the attribute of a particular control. + * @param TControl control element or element id + * @param string attribute name + * @param string attribute value + */ + public function setAttribute($control, $name, $value) + { + // Attributes should be applied on Surrounding tag, except for 'disabled' attribute + if ($control instanceof ISurroundable && strtolower($name)!=='disabled') + $control=$control->getSurroundingTagID(); + $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value)); + } + + /** + * Sets the options of a select input element. + * @param TControl control element or element id + * @param TCollection a list of new options + */ + public function setListItems($control, $items) + { + $options = array(); + if($control instanceof TListControl) + { + $promptText = $control->getPromptText(); + $promptValue = $control->getPromptValue(); + + if($promptValue==='') + $promptValue = $promptText; + + if($promptValue!=='') + $options[] = array($promptText, $promptValue); + } + + foreach($items as $item) + { + if($item->getHasAttributes()) + $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group')); + else + $options[] = array($item->getText(),$item->getValue()); + } + $this->callClientFunction('Prado.Element.setOptions', array($control, $options)); + } + + /** + * Shows an element by changing its CSS display style as empty. + * @param TControl control element or element id + */ + public function show($element) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.show', $element); + } + + /** + * Hides an element by changing its CSS display style to "none". + * @param TControl control element or element id + */ + public function hide($element) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.hide', $element); + } + + /** + * Toggles the visibility of the element. + * @param TControl control element or element id + * @param string visual effect, such as, 'appear' or 'slide' or 'blind'. + * @param array additional options. + */ + public function toggle($element, $effect=null, $options=array()) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.toggle', array($element,$effect,$options)); + } + + /** + * Removes an element from the HTML page. + * @param TControl control element or element id + */ + public function remove($element) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.remove', $element); + } + + public function addPostDataLoader($name) + { + $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name); + } + + /** + * Update the element's innerHTML with new content. + * @param TControl control element or element id + * @param TControl new HTML content, if content is of a TControl, the + * controls render method is called. + */ + public function update($element, $content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content, 'Element.update'); + } + + /** + * Add a Css class name to the element. + * @param TControl control element or element id + * @param string CssClass name to add. + */ + public function addCssClass($element, $cssClass) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.addClassName', array($element, $cssClass)); + } + + /** + * Remove a Css class name from the element. + * @param TControl control element or element id + * @param string CssClass name to remove. + */ + public function removeCssClass($element, $cssClass) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.removeClassName', array($element, $cssClass)); + } + + /** + * Sets the CssClass of an element. + * @param TControl control element or element id + * @param string new CssClass name for the element. + */ + /*public function setCssClass($element, $cssClass) + { + $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass)); + }*/ + + /** + * Scroll the top of the browser viewing area to the location of the + * element. + * @param TControl control element or element id + */ + public function scrollTo($element) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Element.scrollTo', $element); + } + + /** + * Focus on a particular element. + * @param TControl control element or element id. + */ + public function focus($element) + { + $this->callClientFunction('Prado.Element.focus', $element); + } + + /** + * Sets the style of element. The style must be a key-value array where the + * key is the style property and the value is the style value. + * @param TControl control element or element id + * @param array list of key-value pairs as style property and style value. + */ + public function setStyle($element, $styles) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction('Prado.Element.setStyle', array($element, $styles)); + } + + /** + * Append a HTML fragement to the element. + * @param TControl control element or element id + * @param string HTML fragement or the control to be rendered + */ + public function appendContent($element, $content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content, 'Prado.Element.Insert.append'); + } + + /** + * Prepend a HTML fragement to the element. + * @param TControl control element or element id + * @param string HTML fragement or the control to be rendered + */ + public function prependContent($element, $content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content, 'Prado.Element.Insert.prepend'); + } + + /** + * Insert a HTML fragement after the element. + * @param TControl control element or element id + * @param string HTML fragement or the control to be rendered + */ + public function insertContentAfter($element, $content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content, 'Prado.Element.Insert.after'); + } + + /** + * Insert a HTML fragement in before the element. + * @param TControl control element or element id + * @param string HTML fragement or the control to be rendered + */ + public function insertContentBefore($element, $content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content, 'Prado.Element.Insert.before'); + } + + /** + * Replace the content of an element with new content. The new content can + * be a string or a TControl component. If the <tt>content</tt> parameter is + * a TControl component, its rendered method will be called and its contents + * will be used for replacement. + * @param TControl control element or HTML element id. + * @param string HTML fragement or the control to be rendered + * @param string replacement method, default is to replace the outter + * html content. + * @param string provide a custom boundary. + * @see insertAbout + * @see insertBelow + * @see insertBefore + * @see insertAfter + */ + protected function replace($element, $content, $method="Element.replace", $boundary=null) + { + if($content instanceof TControl) + { + $boundary = $this->getRenderedContentBoundary($content); + $content = null; + } + else if($content instanceof THtmlWriter) + { + $boundary = $this->getResponseContentBoundary($content); + $content = null; + } + + $this->callClientFunction('Prado.Element.replace', + array($element, $method, $content, $boundary)); + } + + /** + * Replace the content of an element with new content contained in writer. + * @param TControl control element or HTML element id. + * @param string HTML fragement or the control to be rendered + */ + public function replaceContent($element,$content) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->replace($element, $content); + } + + /** + * Evaluate a block of javascript enclosed in a boundary. + * @param THtmlWriter writer for the content. + */ + public function evaluateScript($writer) + { + $this->replace(null, $writer, 'Prado.Element.evaluateScript'); + } + + /** + * Appends a block of inline javascript enclosed in a boundary. + * Similar to to evaluateScript(), but functions declared in the + * inline block will be available to page elements. + * @param THtmlWriter writer for the content. + */ + public function appendScriptBlock($content) + { + if($content instanceof TControl) + { + $boundary = $this->getRenderedContentBoundary($content); + } + else if($content instanceof THtmlWriter) + { + $boundary = $this->getResponseContentBoundary($content); + } + + $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary)); + } + + /** + * Renders the control and return the content boundary from + * TCallbackResponseWriter. This method should only be used by framework + * component developers. The render() method is defered to be called in the + * TActivePageAdapter class. + * @param TControl control to be rendered on callback response. + * @return string the boundary for which the rendered content is wrapped. + */ + private function getRenderedContentBoundary($control) + { + $writer = $this->getResponse()->createHtmlWriter(); + $adapter = $control->getPage()->getAdapter(); + $adapter->registerControlToRender($control, $writer); + return $writer->getWriter()->getBoundary(); + } + + /** + * @param THtmlWriter the writer responsible for rendering html content. + * @return string content boundary. + */ + private function getResponseContentBoundary($html) + { + if($html instanceof THtmlWriter) + { + if($html->getWriter() instanceof TCallbackResponseWriter) + return $html->getWriter()->getBoundary(); + } + return null; + } + + /** + * Add a visual effect the element. + * @param string visual effect function name. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function visualEffect($type, $element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->callClientFunction($type, array($element, $options)); + } + + /** + * Visual Effect: Gradually make the element appear. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function appear($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Appear', $element, $options); + } + + /** + * Visual Effect: Blind down. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function blindDown($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.BlindDown', $element, $options); + } + + /** + * Visual Effect: Blind up. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function blindUp($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.BlindUp', $element, $options); + + } + + /** + * Visual Effect: Drop out. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function dropOut($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.DropOut', $element, $options); + } + + /** + * Visual Effect: Gradually fade the element. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fade($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Fade', $element, $options); + } + + /** + * Visual Effect: Fold. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fold($element, $options = null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Fold', $element, $options); + } + + /** + * Visual Effect: Gradually make an element grow to a predetermined size. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function grow($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Grow', $element, $options); + } + + /** + * Visual Effect: Gradually grow and fade the element. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function puff($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Puff', $element, $options); + } + + /** + * Visual Effect: Pulsate. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function pulsate($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Pulsate', $element, $options); + } + + /** + * Visual Effect: Shake the element. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function shake($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Shake', $element, $options); + } + + /** + * Visual Effect: Shrink the element. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function shrink($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Shrink', $element, $options); + } + + /** + * Visual Effect: Slide down. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function slideDown($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.SlideDown', $element, $options); + } + + /** + * Visual Effect: Side up. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function slideUp($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.SlideUp', $element, $options); + } + + /** + * Visual Effect: Squish the element. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function squish($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.Squish', $element, $options); + } + + /** + * Visual Effect: Switch Off effect. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function switchOff($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Effect.SwitchOff', $element, $options); + } + + /** + * Visual Effect: High light the element for about 2 seconds. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function highlight($element, $options=null) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $this->visualEffect('Prado.Effect.Highlight', $element, $options); + } + + /** + * Set the opacity on a html element or control. + * @param TControl control element or element id + * @param float opacity value between 1 and 0 + */ + public function setOpacity($element, $value) + { + if ($element instanceof ISurroundable) + $element=$element->getSurroundingTagID(); + $value = TPropertyValue::ensureFloat($value); + $this->callClientFunction('Element.setOpacity', array($element,$value)); + } +} + diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSide.php b/framework/Web/UI/ActiveControls/TCallbackClientSide.php index 10231a1c..0d602fa5 100644 --- a/framework/Web/UI/ActiveControls/TCallbackClientSide.php +++ b/framework/Web/UI/ActiveControls/TCallbackClientSide.php @@ -1,322 +1,322 @@ -<?php
-/**
- * TCallbackClientSide class file
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientSide class.
- *
- * The following client side events are executing in order if the callback
- * request and response are send and received successfuly.
- *
- * - <b>onPreDispatch</b> executed before a request is dispatched.
- * - <b>onUninitialized</b> executed when callback request is uninitialized.
- * - <b>onLoading</b>* executed when callback request is initiated
- * - <b>onLoaded</b>* executed when callback request begins.
- * - <b>onInteractive</b> executed when callback request is in progress.
- * - <b>onComplete</b>executed when callback response returns.
- * - <b>onSuccess</b> executed when callback request returns and is successful.
- * - <b>onFailure</b> executed when callback request returns and fails.
- * - <b>onException</b> raised when callback request fails due to request/response errors.
- *
- * * Note that theses 2 events are not fired correctly by Opera. To make
- * them work in this browser, Prado will fire them just after onPreDispatch.
- *
- * In a general way, onUninitialized, onLoading, onLoaded and onInteractive events
- * are not implemented consistently in all browsers.When cross browser compatibility is
- * needed, it is best to avoid use them
- *
- * The OnSuccess and OnFailure events are raised when the
- * response is returned. A successful request/response will raise
- * OnSuccess event otherwise OnFailure will be raised.
- *
- * - <b>PostState</b> true to collect the form inputs and post them during callback, default is true.
- * - <b>RequestTimeOut</b> The request timeout in milliseconds.
- * - <b>HasPriority</b> true to ensure that the callback request will be sent
- * immediately and will abort existing prioritized requests. It does not affect
- * callbacks that are not prioritized.
- * - <b>EnablePageStateUpdate</b> enable the callback response to enable the
- * viewstate update. This will automatically set HasPriority to true when enabled.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientSide extends TClientSideOptions
-{
- /**
- * Returns javascript statement enclosed within a javascript function.
- * @param string javascript statement
- * @return string javascript statement wrapped in a javascript function
- */
- protected function ensureFunction($javascript)
- {
- return "function(sender, parameter){ {$javascript} }";
- }
-
- /**
- * @param string javascript code to be executed before a request is dispatched.
- */
- public function setOnPreDispatch($javascript)
- {
- $this->setFunction('onPreDispatch', $javascript);
- }
-
- /**
- * @return string javascript code to be executed before a request is dispatched.
- */
- public function getOnPreDispatch()
- {
- return $this->getOption('onPreDispatch');
- }
-
- /**
- * @return string javascript code for client-side onUninitialized event
- */
- public function getOnUninitialized()
- {
- return $this->getOption('onUninitialized');
- }
-
- /**
- * @param string javascript code for client-side onUninitialized event.
- */
- public function setOnUninitialized($javascript)
- {
- $this->setFunction('onUninitialized', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoading event
- */
- public function getOnLoading()
- {
- return $this->getOption('onLoading');
- }
-
- /**
- * @param string javascript code for client-side onLoading event.
- */
- public function setOnLoading($javascript)
- {
- $this->setFunction('onLoading', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoaded event
- */
- public function getOnLoaded()
- {
- return $this->getOption('onLoaded');
- }
-
- /**
- * @param string javascript code for client-side onLoaded event.
- */
- public function setOnLoaded($javascript)
- {
- $this->setFunction('onLoaded', $javascript);
- }
- /**
- * @return string javascript code for client-side onInteractive event
- */
- public function getOnInteractive()
- {
- return $this->getOption('onInteractive');
- }
-
- /**
- * @param string javascript code for client-side onInteractive event.
- */
- public function setOnInteractive($javascript)
- {
- $this->setFunction('onInteractive', $javascript);
- }
- /**
- * @return string javascript code for client-side onComplete event
- */
- public function getOnComplete()
- {
- return $this->getOption('onComplete');
- }
-
- /**
- * @param string javascript code for client-side onComplete event.
- */
- public function setOnComplete($javascript)
- {
- $this->setFunction('onComplete', $javascript);
- }
- /**
- * @return string javascript code for client-side onSuccess event
- */
- public function getOnSuccess()
- {
- return $this->getOption('onSuccess');
- }
-
- /**
- * @param string javascript code for client-side onSuccess event.
- */
- public function setOnSuccess($javascript)
- {
- $this->setFunction('onSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onFailure event
- */
- public function getOnFailure()
- {
- return $this->getOption('onFailure');
- }
-
- /**
- * @param string javascript code for client-side onFailure event.
- */
- public function setOnFailure($javascript)
- {
- $this->setFunction('onFailure', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onException event
- */
- public function getOnException()
- {
- return $this->getOption('onException');
- }
-
- /**
- * @param string javascript code for client-side onException event.
- */
- public function setOnException($javascript)
- {
- $this->setFunction('onException', $javascript);
- }
-
- /**
- * @return boolean true to post the inputs of the form on callback, default
- * is post the inputs on callback.
- */
- public function getPostState()
- {
- return $this->getOption('PostInputs');
- }
-
- /**
- * @param boolean true to post the inputs of the form with callback
- * requests. Default is to post the inputs.
- */
- public function setPostState($value)
- {
- $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return integer callback request timeout.
- */
- public function getRequestTimeOut()
- {
- return $this->getOption('RequestTimeOut');
- }
-
- /**
- * @param integer callback request timeout
- */
- public function setRequestTimeOut($value)
- {
- $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
- }
-
- /**
- * @return boolean true if the callback request has priority and will abort
- * existing prioritized request in order to send immediately. It does not
- * affect callbacks that are not prioritized. Default is true.
- */
- public function getHasPriority()
- {
- $option = $this->getOption('HasPriority');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @param boolean true to ensure that the callback request will be sent
- * immediately and will abort existing prioritized requests. It does not
- * affect callbacks that are not prioritized.
- */
- public function setHasPriority($value)
- {
- $hasPriority = TPropertyValue::ensureBoolean($value);
- $this->setOption('HasPriority', $hasPriority);
- if(!$hasPriority)
- $this->setEnablePageStateUpdate(false);
- }
-
- /**
- * Set to true to enable the callback response to enable the viewstate
- * update. This will automatically set HasPrority to true.
- * @param boolean true enables the callback response to update the
- * viewstate.
- */
- public function setEnablePageStateUpdate($value)
- {
- $enabled = TPropertyValue::ensureBoolean($value);
- $this->setOption('EnablePageStateUpdate', $enabled);
- if($enabled)
- $this->setHasPriority(true);
- }
-
- /**
- * @return boolean client-side viewstate will be updated on callback
- * response if true. Default is true.
- */
- public function getEnablePageStateUpdate()
- {
- $option = $this->getOption('EnablePageStateUpdate');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @return string post back target ID
- */
- public function getPostBackTarget()
- {
- return $this->getOption('EventTarget');
- }
-
- /**
- * @param string post back target ID
- */
- public function setPostBackTarget($value)
- {
- if($value instanceof TControl)
- $value = $value->getUniqueID();
- $this->setOption('EventTarget', $value);
- }
-
- /**
- * @return string post back event parameter.
- */
- public function getPostBackParameter()
- {
- return $this->getOption('EventParameter');
- }
-
- /**
- * @param string post back event parameter.
- */
- public function setPostBackParameter($value)
- {
- $this->setOption('EventParameter', $value);
- }
-}
-
+<?php +/** + * TCallbackClientSide class file + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackClientSide class. + * + * The following client side events are executing in order if the callback + * request and response are send and received successfuly. + * + * - <b>onPreDispatch</b> executed before a request is dispatched. + * - <b>onUninitialized</b> executed when callback request is uninitialized. + * - <b>onLoading</b>* executed when callback request is initiated + * - <b>onLoaded</b>* executed when callback request begins. + * - <b>onInteractive</b> executed when callback request is in progress. + * - <b>onComplete</b>executed when callback response returns. + * - <b>onSuccess</b> executed when callback request returns and is successful. + * - <b>onFailure</b> executed when callback request returns and fails. + * - <b>onException</b> raised when callback request fails due to request/response errors. + * + * * Note that theses 2 events are not fired correctly by Opera. To make + * them work in this browser, Prado will fire them just after onPreDispatch. + * + * In a general way, onUninitialized, onLoading, onLoaded and onInteractive events + * are not implemented consistently in all browsers.When cross browser compatibility is + * needed, it is best to avoid use them + * + * The OnSuccess and OnFailure events are raised when the + * response is returned. A successful request/response will raise + * OnSuccess event otherwise OnFailure will be raised. + * + * - <b>PostState</b> true to collect the form inputs and post them during callback, default is true. + * - <b>RequestTimeOut</b> The request timeout in milliseconds. + * - <b>HasPriority</b> true to ensure that the callback request will be sent + * immediately and will abort existing prioritized requests. It does not affect + * callbacks that are not prioritized. + * - <b>EnablePageStateUpdate</b> enable the callback response to enable the + * viewstate update. This will automatically set HasPriority to true when enabled. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackClientSide extends TClientSideOptions +{ + /** + * Returns javascript statement enclosed within a javascript function. + * @param string javascript statement + * @return string javascript statement wrapped in a javascript function + */ + protected function ensureFunction($javascript) + { + return "function(sender, parameter){ {$javascript} }"; + } + + /** + * @param string javascript code to be executed before a request is dispatched. + */ + public function setOnPreDispatch($javascript) + { + $this->setFunction('onPreDispatch', $javascript); + } + + /** + * @return string javascript code to be executed before a request is dispatched. + */ + public function getOnPreDispatch() + { + return $this->getOption('onPreDispatch'); + } + + /** + * @return string javascript code for client-side onUninitialized event + */ + public function getOnUninitialized() + { + return $this->getOption('onUninitialized'); + } + + /** + * @param string javascript code for client-side onUninitialized event. + */ + public function setOnUninitialized($javascript) + { + $this->setFunction('onUninitialized', $javascript); + } + + /** + * @return string javascript code for client-side onLoading event + */ + public function getOnLoading() + { + return $this->getOption('onLoading'); + } + + /** + * @param string javascript code for client-side onLoading event. + */ + public function setOnLoading($javascript) + { + $this->setFunction('onLoading', $javascript); + } + + /** + * @return string javascript code for client-side onLoaded event + */ + public function getOnLoaded() + { + return $this->getOption('onLoaded'); + } + + /** + * @param string javascript code for client-side onLoaded event. + */ + public function setOnLoaded($javascript) + { + $this->setFunction('onLoaded', $javascript); + } + /** + * @return string javascript code for client-side onInteractive event + */ + public function getOnInteractive() + { + return $this->getOption('onInteractive'); + } + + /** + * @param string javascript code for client-side onInteractive event. + */ + public function setOnInteractive($javascript) + { + $this->setFunction('onInteractive', $javascript); + } + /** + * @return string javascript code for client-side onComplete event + */ + public function getOnComplete() + { + return $this->getOption('onComplete'); + } + + /** + * @param string javascript code for client-side onComplete event. + */ + public function setOnComplete($javascript) + { + $this->setFunction('onComplete', $javascript); + } + /** + * @return string javascript code for client-side onSuccess event + */ + public function getOnSuccess() + { + return $this->getOption('onSuccess'); + } + + /** + * @param string javascript code for client-side onSuccess event. + */ + public function setOnSuccess($javascript) + { + $this->setFunction('onSuccess', $javascript); + } + + /** + * @return string javascript code for client-side onFailure event + */ + public function getOnFailure() + { + return $this->getOption('onFailure'); + } + + /** + * @param string javascript code for client-side onFailure event. + */ + public function setOnFailure($javascript) + { + $this->setFunction('onFailure', $javascript); + } + + /** + * @return string javascript code for client-side onException event + */ + public function getOnException() + { + return $this->getOption('onException'); + } + + /** + * @param string javascript code for client-side onException event. + */ + public function setOnException($javascript) + { + $this->setFunction('onException', $javascript); + } + + /** + * @return boolean true to post the inputs of the form on callback, default + * is post the inputs on callback. + */ + public function getPostState() + { + return $this->getOption('PostInputs'); + } + + /** + * @param boolean true to post the inputs of the form with callback + * requests. Default is to post the inputs. + */ + public function setPostState($value) + { + $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value)); + } + + /** + * @return integer callback request timeout. + */ + public function getRequestTimeOut() + { + return $this->getOption('RequestTimeOut'); + } + + /** + * @param integer callback request timeout + */ + public function setRequestTimeOut($value) + { + $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value)); + } + + /** + * @return boolean true if the callback request has priority and will abort + * existing prioritized request in order to send immediately. It does not + * affect callbacks that are not prioritized. Default is true. + */ + public function getHasPriority() + { + $option = $this->getOption('HasPriority'); + return ($option===null) ? true : $option; + } + + /** + * @param boolean true to ensure that the callback request will be sent + * immediately and will abort existing prioritized requests. It does not + * affect callbacks that are not prioritized. + */ + public function setHasPriority($value) + { + $hasPriority = TPropertyValue::ensureBoolean($value); + $this->setOption('HasPriority', $hasPriority); + if(!$hasPriority) + $this->setEnablePageStateUpdate(false); + } + + /** + * Set to true to enable the callback response to enable the viewstate + * update. This will automatically set HasPrority to true. + * @param boolean true enables the callback response to update the + * viewstate. + */ + public function setEnablePageStateUpdate($value) + { + $enabled = TPropertyValue::ensureBoolean($value); + $this->setOption('EnablePageStateUpdate', $enabled); + if($enabled) + $this->setHasPriority(true); + } + + /** + * @return boolean client-side viewstate will be updated on callback + * response if true. Default is true. + */ + public function getEnablePageStateUpdate() + { + $option = $this->getOption('EnablePageStateUpdate'); + return ($option===null) ? true : $option; + } + + /** + * @return string post back target ID + */ + public function getPostBackTarget() + { + return $this->getOption('EventTarget'); + } + + /** + * @param string post back target ID + */ + public function setPostBackTarget($value) + { + if($value instanceof TControl) + $value = $value->getUniqueID(); + $this->setOption('EventTarget', $value); + } + + /** + * @return string post back event parameter. + */ + public function getPostBackParameter() + { + return $this->getOption('EventParameter'); + } + + /** + * @param string post back event parameter. + */ + public function setPostBackParameter($value) + { + $this->setOption('EventParameter', $value); + } +} + diff --git a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php index d4038fb5..7c532588 100644 --- a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php +++ b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php @@ -1,87 +1,87 @@ -<?php
-/**
- * TCallbackEventParameter class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackEventParameter class.
- *
- * The TCallbackEventParameter provides the parameter passed during the callback
- * request in the {@link getCallbackParameter CallbackParameter} property. The
- * callback response content (e.g. new HTML content) must be rendered
- * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
- * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
- *
- * Each instance TCallbackResponseWriter is associated with a unique
- * boundary delimited. By default each panel only renders its own content.
- * To replace the content of ONE panel with that of rendered from multiple panels
- * use the same writer instance for the panels to be rendered.
- *
- * The response data (i.e., passing results back to the client-side
- * callback handler function) can be set using {@link setResponseData ResponseData} property.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackEventParameter extends TEventParameter
-{
- /**
- * @var THttpResponse output content.
- */
- private $_response;
- /**
- * @var mixed callback request parameter.
- */
- private $_parameter;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter)
- {
- $this->_response = $response;
- $this->_parameter = $parameter;
- }
-
- /**
- * @return TCallbackResponseWriter holds the response content.
- */
- public function getNewWriter()
- {
- return $this->_response->createHtmlWriter(null);
- }
-
- /**
- * @return mixed callback request parameter.
- */
- public function getCallbackParameter()
- {
- return $this->_parameter;
- }
-
- /**
- * @param mixed callback response data.
- */
- public function setResponseData($value)
- {
- $this->_response->getAdapter()->setResponseData($value);
- }
-
- /**
- * @return mixed callback response data.
- */
- public function getResponseData()
- {
- return $this->_response->getAdapter()->getResponseData();
- }
-}
-
+<?php +/** + * TCallbackEventParameter class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackEventParameter class. + * + * The TCallbackEventParameter provides the parameter passed during the callback + * request in the {@link getCallbackParameter CallbackParameter} property. The + * callback response content (e.g. new HTML content) must be rendered + * using an THtmlWriter obtained from the {@link getNewWriter NewWriter} + * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter. + * + * Each instance TCallbackResponseWriter is associated with a unique + * boundary delimited. By default each panel only renders its own content. + * To replace the content of ONE panel with that of rendered from multiple panels + * use the same writer instance for the panels to be rendered. + * + * The response data (i.e., passing results back to the client-side + * callback handler function) can be set using {@link setResponseData ResponseData} property. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackEventParameter extends TEventParameter +{ + /** + * @var THttpResponse output content. + */ + private $_response; + /** + * @var mixed callback request parameter. + */ + private $_parameter; + + /** + * Creates a new TCallbackEventParameter. + */ + public function __construct($response, $parameter) + { + $this->_response = $response; + $this->_parameter = $parameter; + } + + /** + * @return TCallbackResponseWriter holds the response content. + */ + public function getNewWriter() + { + return $this->_response->createHtmlWriter(null); + } + + /** + * @return mixed callback request parameter. + */ + public function getCallbackParameter() + { + return $this->_parameter; + } + + /** + * @param mixed callback response data. + */ + public function setResponseData($value) + { + $this->_response->getAdapter()->setResponseData($value); + } + + /** + * @return mixed callback response data. + */ + public function getResponseData() + { + return $this->_response->getAdapter()->getResponseData(); + } +} + diff --git a/framework/Web/UI/ActiveControls/TCallbackOptions.php b/framework/Web/UI/ActiveControls/TCallbackOptions.php index baba32e1..e75c2fde 100644 --- a/framework/Web/UI/ActiveControls/TCallbackOptions.php +++ b/framework/Web/UI/ActiveControls/TCallbackOptions.php @@ -1,53 +1,53 @@ -<?php
-/**
- * TCallbackOptions component class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackOptions class.
- *
- * TCallbackOptions allows common set of callback client-side options
- * to be attached to other active controls.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackOptions extends TControl
-{
- /**
- * @var TCallbackClientSide client side callback options.
- */
- private $_clientSide;
-
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g. <com:TCallbackOptions ClientSide.OnSuccess="..." />
- * See {@link TCallbackClientSide} for details on the properties of
- * ClientSide.
- * @return TCallbackClientSide client-side callback options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientSide();
- return $this->_clientSide;
- }
-
- /**
- * @return TCallbackClientSide callback client-side options.
- */
- protected function createClientSide()
- {
- return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide');
- }
-}
-
+<?php +/** + * TCallbackOptions component class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackOptions class. + * + * TCallbackOptions allows common set of callback client-side options + * to be attached to other active controls. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackOptions extends TControl +{ + /** + * @var TCallbackClientSide client side callback options. + */ + private $_clientSide; + + /** + * Callback client-side options can be set by setting the properties of + * the ClientSide property. E.g. <com:TCallbackOptions ClientSide.OnSuccess="..." /> + * See {@link TCallbackClientSide} for details on the properties of + * ClientSide. + * @return TCallbackClientSide client-side callback options. + */ + public function getClientSide() + { + if($this->_clientSide===null) + $this->_clientSide = $this->createClientSide(); + return $this->_clientSide; + } + + /** + * @return TCallbackClientSide callback client-side options. + */ + protected function createClientSide() + { + return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide'); + } +} + diff --git a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php index c28b435c..38aaabec 100644 --- a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php +++ b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php @@ -1,95 +1,95 @@ -<?php
-/**
- * TEventTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TEventTriggeredCallback Class
- *
- * Triggers a new callback request when a particular {@link setEventName EventName}
- * on a control with ID given by {@link setControlID ControlID} is raised.
- *
- * The default action of the event on the client-side can be prevented when
- * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TEventTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The client-side event name the trigger listens to.
- */
- public function getEventName()
- {
- return $this->getViewState('EventName', '');
- }
-
- /**
- * Sets the client-side event name that fires the callback request.
- * @param string The client-side event name the trigger listens to.
- */
- public function setEventName($value)
- {
- $this->setViewState('EventName', $value, '');
- }
-
- /**
- * @param boolean true to prevent/stop default event action.
- */
- public function setPreventDefaultAction($value)
- {
- $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
- }
-
- /**
- * @return boolean true to prevent/stop default event action.
- */
- public function getPreventDefaultAction()
- {
- return $this->getViewState('StopEvent', false);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $name = preg_replace('/^on/', '', $this->getEventName());
- $options['EventName'] = strtolower($name);
- $options['StopEvent'] = $this->getPreventDefaultAction();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEventTriggeredCallback';
- }
-}
-
+<?php +/** + * TEventTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback'); + +/** + * TEventTriggeredCallback Class + * + * Triggers a new callback request when a particular {@link setEventName EventName} + * on a control with ID given by {@link setControlID ControlID} is raised. + * + * The default action of the event on the client-side can be prevented when + * {@link setPreventDefaultAction PreventDefaultAction} is set to true. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TEventTriggeredCallback extends TTriggeredCallback +{ + /** + * @return string The client-side event name the trigger listens to. + */ + public function getEventName() + { + return $this->getViewState('EventName', ''); + } + + /** + * Sets the client-side event name that fires the callback request. + * @param string The client-side event name the trigger listens to. + */ + public function setEventName($value) + { + $this->setViewState('EventName', $value, ''); + } + + /** + * @param boolean true to prevent/stop default event action. + */ + public function setPreventDefaultAction($value) + { + $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false); + } + + /** + * @return boolean true to prevent/stop default event action. + */ + public function getPreventDefaultAction() + { + return $this->getViewState('StopEvent', false); + } + + /** + * @return array list of timer options for client-side. + */ + protected function getTriggerOptions() + { + $options = parent::getTriggerOptions(); + $name = preg_replace('/^on/', '', $this->getEventName()); + $options['EventName'] = strtolower($name); + $options['StopEvent'] = $this->getPreventDefaultAction(); + return $options; + } + + /** + * Registers the javascript code for initializing the active control. + * @param THtmlWriter the renderer. + */ + public function render($writer) + { + parent::render($writer); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getTriggerOptions()); + } + + /** + * @return string corresponding javascript class name for TEventTriggeredCallback. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TEventTriggeredCallback'; + } +} + diff --git a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php index aba477b9..47c8aeac 100644 --- a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php +++ b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php @@ -1,290 +1,290 @@ -<?php
-/**
- * TInPlaceTextBox class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-
-/**
- * TInPlaceTextBox Class
- * *
- * TInPlaceTextBox is a component rendered as a label and allows its
- * contents to be edited by changing the label to a textbox when
- * the label is clicked or when another control or html element with
- * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
- *
- * If the {@link OnLoadingText} event is handled, a callback request is
- * made when the label is clicked, while the request is being made the
- * textbox is disabled from editing. The {@link OnLoadingText} event allows
- * you to update the content of the textbox before the client is allowed
- * to edit the content. After the callback request returns successfully,
- * the textbox is enabled and the contents is then allowed to be edited.
- *
- * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
- * is true and the textbox content has changed, a callback request is made and
- * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
- * During the request, the textbox is disabled.
- *
- * After the callback request returns sucessfully, the textbox is enabled.
- * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
- * the textbox will be hidden and the label is then shown.
- *
- * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
- * the control not editable. This property can be also changed on callback
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInPlaceTextBox extends TActiveTextBox
-{
- /**
- * Sets the auto post back to true by default.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAutoPostBack(true);
- }
-
- /**
- * @param boolean true to hide the textbox after losing focus.
- */
- public function setAutoHideTextBox($value)
- {
- $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true will hide the textbox after losing focus.
- */
- public function getAutoHideTextBox()
- {
- return $this->getViewState('AutoHide', true);
- }
-
- /**
- * @param boolean true to display the edit textbox
- */
- public function setDisplayTextBox($value)
- {
- $value = TPropertyValue::ensureBoolean($value);
- $this->setViewState('DisplayTextBox', $value,false);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->callClientFunction('setDisplayTextBox',$value);
- }
-
- /**
- * @return boolean true to display the edit textbox
- */
- public function getDisplayTextBox()
- {
- return $this->getViewState('DisplayTextBox', false);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- $client = $this->getPage()->getCallbackClient();
- $code = $this->getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
-
- /**
- * @param string ID of the control that can trigger to edit the textbox
- */
- public function setEditTriggerControlID($value)
- {
- $this->setViewState('EditTriggerControlID', $value);
- }
-
- /**
- * @return string ID of the control that can trigger to edit the textbox
- */
- public function getEditTriggerControlID()
- {
- return $this->getViewState('EditTriggerControlID');
- }
-
- /**
- * @return string edit trigger control client ID.
- */
- protected function getExternalControlID()
- {
- $extID = $this->getEditTriggerControlID();
- if($extID===null) return '';
- if(($control = $this->findControl($extID))!==null)
- return $control->getClientID();
- return $extID;
- }
-
- /**
- * On callback response, the inner HTMl of the label and the
- * value of the textbox is updated
- * @param string the text value of the label
- */
- public function setText($value)
- {
- TTextBox::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $client->update($this->getLabelClientID(), $value);
- $client->setValue($this, $value);
- }
- }
-
- /**
- * Update ClientSide Readonly property
- * @param boolean value
- * @since 3.1.2
- */
- public function setReadOnly ($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- TTextBox::setReadOnly($value);
- if ($this->getActiveControl()->canUpdateClientSide())
- {
- $this->callClientFunction('setReadOnly', $value);
- }
- }
-
- /**
- * @return string tag name of the label.
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Renders the body content of the label.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string label client ID
- */
- protected function getLabelClientID()
- {
- return $this->getClientID().'__label';
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $action = $param->getCallbackParameter();
- if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
- {
- $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
- $this->onLoadingText($parameter);
- }
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @return array callback options.
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['ID'] = $this->getLabelClientID();
- $options['TextBoxID'] = $this->getClientID();
- $options['ExternalControl'] = $this->getExternalControlID();
- $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
- $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
- $options['Columns'] = $this->getColumns();
- if($this->getTextMode()==='MultiLine')
- {
- $options['Rows'] = $this->getRows();
- $options['Wrap'] = $this->getWrap()== false ? '' : true;
- }
- else
- {
- $length = $this->getMaxLength();
- $options['MaxLength'] = $length > 0 ? $length : '';
- }
-
- if($this->hasEventHandler('OnLoadingText'))
- $options['LoadTextOnEdit'] = true;
-
- $options['ReadOnly']=$this->getReadOnly();
- return $options;
- }
-
- /**
- * Raised when editing the content is requsted to be loaded from the
- * server side.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onLoadingText($param)
- {
- $this->raiseEvent('OnLoadingText',$this,$param);
- }
-
- /**
- * @return string corresponding javascript class name for this TInPlaceTextBox
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TInPlaceTextBox';
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
- TWebControl::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getLabelClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->registerClientScript();
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('inlineeditor');
- }
-}
+<?php +/** + * TInPlaceTextBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TActiveTextBox'); + +/** + * TInPlaceTextBox Class + * * + * TInPlaceTextBox is a component rendered as a label and allows its + * contents to be edited by changing the label to a textbox when + * the label is clicked or when another control or html element with + * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked. + * + * If the {@link OnLoadingText} event is handled, a callback request is + * made when the label is clicked, while the request is being made the + * textbox is disabled from editing. The {@link OnLoadingText} event allows + * you to update the content of the textbox before the client is allowed + * to edit the content. After the callback request returns successfully, + * the textbox is enabled and the contents is then allowed to be edited. + * + * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack} + * is true and the textbox content has changed, a callback request is made and + * the {@link OnTextChanged} event is raised like that of the TActiveTextBox. + * During the request, the textbox is disabled. + * + * After the callback request returns sucessfully, the textbox is enabled. + * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then + * the textbox will be hidden and the label is then shown. + * + * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make + * the control not editable. This property can be also changed on callback + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TInPlaceTextBox extends TActiveTextBox +{ + /** + * Sets the auto post back to true by default. + */ + public function __construct() + { + parent::__construct(); + $this->setAutoPostBack(true); + } + + /** + * @param boolean true to hide the textbox after losing focus. + */ + public function setAutoHideTextBox($value) + { + $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return boolean true will hide the textbox after losing focus. + */ + public function getAutoHideTextBox() + { + return $this->getViewState('AutoHide', true); + } + + /** + * @param boolean true to display the edit textbox + */ + public function setDisplayTextBox($value) + { + $value = TPropertyValue::ensureBoolean($value); + $this->setViewState('DisplayTextBox', $value,false); + if($this->getActiveControl()->canUpdateClientSide()) + $this->callClientFunction('setDisplayTextBox',$value); + } + + /** + * @return boolean true to display the edit textbox + */ + public function getDisplayTextBox() + { + return $this->getViewState('DisplayTextBox', false); + } + + /** + * Calls the client-side static method for this control class. + * @param string static method name + * @param mixed method parmaeter + */ + protected function callClientFunction($func,$value) + { + $client = $this->getPage()->getCallbackClient(); + $code = $this->getClientClassName().'.'.$func; + $client->callClientFunction($code,array($this,$value)); + } + + /** + * @param string ID of the control that can trigger to edit the textbox + */ + public function setEditTriggerControlID($value) + { + $this->setViewState('EditTriggerControlID', $value); + } + + /** + * @return string ID of the control that can trigger to edit the textbox + */ + public function getEditTriggerControlID() + { + return $this->getViewState('EditTriggerControlID'); + } + + /** + * @return string edit trigger control client ID. + */ + protected function getExternalControlID() + { + $extID = $this->getEditTriggerControlID(); + if($extID===null) return ''; + if(($control = $this->findControl($extID))!==null) + return $control->getClientID(); + return $extID; + } + + /** + * On callback response, the inner HTMl of the label and the + * value of the textbox is updated + * @param string the text value of the label + */ + public function setText($value) + { + TTextBox::setText($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + $client = $this->getPage()->getCallbackClient(); + $client->update($this->getLabelClientID(), $value); + $client->setValue($this, $value); + } + } + + /** + * Update ClientSide Readonly property + * @param boolean value + * @since 3.1.2 + */ + public function setReadOnly ($value) + { + $value=TPropertyValue::ensureBoolean($value); + TTextBox::setReadOnly($value); + if ($this->getActiveControl()->canUpdateClientSide()) + { + $this->callClientFunction('setReadOnly', $value); + } + } + + /** + * @return string tag name of the label. + */ + protected function getTagName() + { + return 'span'; + } + + /** + * Renders the body content of the label. + * @param THtmlWriter the writer for rendering + */ + public function renderContents($writer) + { + if(($text=$this->getText())==='') + parent::renderContents($writer); + else + $writer->write($text); + } + + /** + * @return string label client ID + */ + protected function getLabelClientID() + { + return $this->getClientID().'__label'; + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCallback' event to fire up the event handlers. If you override this + * method, be sure to call the parent implementation so that the event + * handler can be invoked. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onCallback($param) + { + $action = $param->getCallbackParameter(); + if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__') + { + $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]); + $this->onLoadingText($parameter); + } + $this->raiseEvent('OnCallback', $this, $param); + } + + /** + * @return array callback options. + */ + protected function getPostBackOptions() + { + $options = parent::getPostBackOptions(); + $options['ID'] = $this->getLabelClientID(); + $options['TextBoxID'] = $this->getClientID(); + $options['ExternalControl'] = $this->getExternalControlID(); + $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true; + $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true; + $options['Columns'] = $this->getColumns(); + if($this->getTextMode()==='MultiLine') + { + $options['Rows'] = $this->getRows(); + $options['Wrap'] = $this->getWrap()== false ? '' : true; + } + else + { + $length = $this->getMaxLength(); + $options['MaxLength'] = $length > 0 ? $length : ''; + } + + if($this->hasEventHandler('OnLoadingText')) + $options['LoadTextOnEdit'] = true; + + $options['ReadOnly']=$this->getReadOnly(); + return $options; + } + + /** + * Raised when editing the content is requsted to be loaded from the + * server side. + * @param TCallbackEventParameter event parameter to be passed to the event handlers + */ + public function onLoadingText($param) + { + $this->raiseEvent('OnLoadingText',$this,$param); + } + + /** + * @return string corresponding javascript class name for this TInPlaceTextBox + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TInPlaceTextBox'; + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + //calls the TWebControl to avoid rendering other attribute normally render for a textbox. + TWebControl::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getLabelClientID()); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * Registers CSS and JS. + * This method is invoked right before the control rendering, if the control is visible. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->registerClientScript(); + } + + /** + * Registers the relevant JavaScript. + */ + protected function registerClientScript() + { + $cs=$this->getPage()->getClientScript(); + $cs->registerPradoScript('inlineeditor'); + } +} diff --git a/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/framework/Web/UI/ActiveControls/TTriggeredCallback.php index fd1fabb1..4b89cb8e 100644 --- a/framework/Web/UI/ActiveControls/TTriggeredCallback.php +++ b/framework/Web/UI/ActiveControls/TTriggeredCallback.php @@ -1,71 +1,71 @@ -<?php
-/**
- * TTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallback');
-/**
- * TTriggeredCallback abstract Class
- *
- * Base class for triggered callback controls. The {@link setControlID ControlID}
- * property sets the control ID to observe the trigger.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TTriggeredCallback extends TCallback
-{
- /**
- * @return string The ID of the server control the trigger is bounded to.
- */
- public function getControlID()
- {
- return $this->getViewState('ControlID', '');
- }
-
- /**
- * @param string The ID of the server control the trigger is bounded to.
- */
- public function setControlID($value)
- {
- $this->setViewState('ControlID', $value, '');
- }
-
- /**
- * @return string target control client ID or html element ID if
- * control is not found in hierarchy.
- */
- protected function getTargetControl()
- {
- $id = $this->getControlID();
- if(($control=$this->findControl($id)) instanceof TControl)
- return $control->getClientID();
- if($id==='')
- {
- throw new TConfigurationException(
- 'ttriggeredcallback_invalid_controlid', get_class($this));
- }
- return $id;
- }
-
- /**
- * @return array list of trigger callback options.
- */
- protected function getTriggerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['ControlID'] = $this->getTargetControl();
- return $options;
- }
-}
-
+<?php +/** + * TTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TCallback'); +/** + * TTriggeredCallback abstract Class + * + * Base class for triggered callback controls. The {@link setControlID ControlID} + * property sets the control ID to observe the trigger. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +abstract class TTriggeredCallback extends TCallback +{ + /** + * @return string The ID of the server control the trigger is bounded to. + */ + public function getControlID() + { + return $this->getViewState('ControlID', ''); + } + + /** + * @param string The ID of the server control the trigger is bounded to. + */ + public function setControlID($value) + { + $this->setViewState('ControlID', $value, ''); + } + + /** + * @return string target control client ID or html element ID if + * control is not found in hierarchy. + */ + protected function getTargetControl() + { + $id = $this->getControlID(); + if(($control=$this->findControl($id)) instanceof TControl) + return $control->getClientID(); + if($id==='') + { + throw new TConfigurationException( + 'ttriggeredcallback_invalid_controlid', get_class($this)); + } + return $id; + } + + /** + * @return array list of trigger callback options. + */ + protected function getTriggerOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + $options['ControlID'] = $this->getTargetControl(); + return $options; + } +} + diff --git a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php index 58a78d08..899419ee 100644 --- a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php +++ b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php @@ -1,120 +1,120 @@ -<?php
-/**
- * TValueTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TValueTriggeredCallback Class
- *
- * Observes the value with {@link setPropertyName PropertyName} of a
- * control with {@link setControlID ControlID}. Changes to the observed
- * property value will trigger a new callback request. The property value is checked
- * for changes every{@link setInterval Interval} seconds.
- *
- * A {@link setDecayRate DecayRate} can be set to increase the polling
- * interval linearly if no changes are observed. Once a change is
- * observed, the polling interval is reset to the original value.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TValueTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The control property name to observe value changes.
- */
- public function getPropertyName()
- {
- return $this->getViewState('PropertyName', '');
- }
-
- /**
- * Sets the control property name to observe value changes that fires the callback request.
- * @param string The control property name to observe value changes.
- */
- public function setPropertyName($value)
- {
- $this->setViewState('PropertyName', $value, '');
- }
-
- /**
- * Sets the polling interval in seconds to observe property changes.
- * Default is 1 second.
- * @param float polling interval in seconds.
- */
- public function setInterval($value)
- {
- $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
- }
-
- /**
- * @return float polling interval, 1 second default.
- */
- public function getInterval()
- {
- return $this->getViewState('Interval', 1);
- }
-
- /**
- * Gets the decay rate between callbacks. Default is 0;
- * @return float decay rate between callbacks.
- */
- public function getDecayRate()
- {
- return $this->getViewState('Decay', 0);
- }
-
- /**
- * Sets the decay rate between callback. Default is 0;
- * @param float decay rate between callbacks.
- */
- public function setDecayRate($value)
- {
- $decay = TPropertyValue::ensureFloat($value);
- if($decay < 0)
- throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
- $this->setViewState('Decay', $decay);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $options['PropertyName'] = $this->getPropertyName();
- $options['Interval'] = $this->getInterval();
- $options['Decay'] = $this->getDecayRate();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TValueTriggeredCallback';
- }
-}
+<?php +/** + * TValueTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ + +Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback'); + +/** + * TValueTriggeredCallback Class + * + * Observes the value with {@link setPropertyName PropertyName} of a + * control with {@link setControlID ControlID}. Changes to the observed + * property value will trigger a new callback request. The property value is checked + * for changes every{@link setInterval Interval} seconds. + * + * A {@link setDecayRate DecayRate} can be set to increase the polling + * interval linearly if no changes are observed. Once a change is + * observed, the polling interval is reset to the original value. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TValueTriggeredCallback extends TTriggeredCallback +{ + /** + * @return string The control property name to observe value changes. + */ + public function getPropertyName() + { + return $this->getViewState('PropertyName', ''); + } + + /** + * Sets the control property name to observe value changes that fires the callback request. + * @param string The control property name to observe value changes. + */ + public function setPropertyName($value) + { + $this->setViewState('PropertyName', $value, ''); + } + + /** + * Sets the polling interval in seconds to observe property changes. + * Default is 1 second. + * @param float polling interval in seconds. + */ + public function setInterval($value) + { + $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1); + } + + /** + * @return float polling interval, 1 second default. + */ + public function getInterval() + { + return $this->getViewState('Interval', 1); + } + + /** + * Gets the decay rate between callbacks. Default is 0; + * @return float decay rate between callbacks. + */ + public function getDecayRate() + { + return $this->getViewState('Decay', 0); + } + + /** + * Sets the decay rate between callback. Default is 0; + * @param float decay rate between callbacks. + */ + public function setDecayRate($value) + { + $decay = TPropertyValue::ensureFloat($value); + if($decay < 0) + throw new TConfigurationException('callback_decay_be_not_negative', $this->getID()); + $this->setViewState('Decay', $decay); + } + + /** + * @return array list of timer options for client-side. + */ + protected function getTriggerOptions() + { + $options = parent::getTriggerOptions(); + $options['PropertyName'] = $this->getPropertyName(); + $options['Interval'] = $this->getInterval(); + $options['Decay'] = $this->getDecayRate(); + return $options; + } + + /** + * Registers the javascript code for initializing the active control. + * @param THtmlWriter the renderer. + */ + public function render($writer) + { + parent::render($writer); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getTriggerOptions()); + } + + /** + * @return string corresponding javascript class name for TEventTriggeredCallback. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TValueTriggeredCallback'; + } +} diff --git a/framework/Web/UI/TCachePageStatePersister.php b/framework/Web/UI/TCachePageStatePersister.php index 486c87ca..34b9203a 100644 --- a/framework/Web/UI/TCachePageStatePersister.php +++ b/framework/Web/UI/TCachePageStatePersister.php @@ -1,200 +1,200 @@ -<?php
-/**
- * TCachePageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCachePageStatePersister class
- *
- * TCachePageStatePersister implements a page state persistent method based on cache.
- * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
- * is passed to the client side to identify the state. This greatly reduces the size of
- * the page state that needs to be transmitted between the server and the client. Of course,
- * this is at the cost of using server side resource.
- *
- * A cache module has to be loaded in order to use TCachePageStatePersister.
- * By default, TCachePageStatePersister will use the primary cache module.
- * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
- * Any cache module, as long as it implements the interface {@link ICache}, may be used.
- * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
- *
- * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
- * that stores in cache.
- *
- * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
- * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
- *
- * There are a couple of ways to use TCachePageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TCachePageStatePersister instance there.
- * Or one can configure the pages to use TCachePageStatePersister in page configurations
- * as follows,
- * <code>
- * <pages StatePersisterClass="System.Web.UI.TCachePageStatePersister"
- * StatePersister.CacheModuleID="mycache"
- * StatePersister.CacheTimeout="3600" />
- * </code>
- * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
- * for the TCachePageStatePersister instance.
- *
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TCachePageStatePersister, use
- * <code>
- * <pages>
- * <page id="PageID" StatePersisterClass="System.Web.UI.TCachePageStatePersister" />
- * </pages>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1.1
- */
-class TCachePageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_prefix='statepersister';
- private $_page;
- private $_cache=null;
- private $_cacheModuleID='';
- private $_timeout=1800;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return string the ID of the cache module.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If not set, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * @return ICache the cache module being used for data storage
- */
- public function getCache()
- {
- if($this->_cache===null)
- {
- if($this->_cacheModuleID!=='')
- $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
- else
- $cache=Prado::getApplication()->getCache();
- if($cache===null || !($cache instanceof ICache))
- {
- if($this->_cacheModuleID!=='')
- throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
- else
- throw new TConfigurationException('cachepagestatepersister_cache_required');
- }
- $this->_cache=$cache;
- }
- return $this->_cache;
- }
-
- /**
- * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
- */
- public function getCacheTimeout()
- {
- return $this->_timeout;
- }
-
- /**
- * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
- * @throws TInvalidDataValueException if the number is smaller than 0.
- */
- public function setCacheTimeout($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>=0)
- $this->_timeout=$value;
- else
- throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
- }
-
- /**
- * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
- */
- public function getKeyPrefix()
- {
- return $this->_prefix;
- }
-
- /**
- * @param string prefix of cache variable name to avoid conflict with other cache data
- */
- public function setKeyPrefix($value)
- {
- $this->_prefix=$value;
- }
-
- /**
- * @param string micro timestamp when saving state occurs
- * @return string a key that is unique per user request
- */
- protected function calculateKey($timestamp)
- {
- return $this->getKeyPrefix().':'
- . $this->_page->getRequest()->getUserHostAddress()
- . $this->_page->getPagePath()
- . $timestamp;
- }
-
- /**
- * Saves state in cache.
- * @param mixed state to be stored
- */
- public function save($data)
- {
- $timestamp=(string)microtime(true);
- $key=$this->calculateKey($timestamp);
- $this->getCache()->add($key,$data,$this->_timeout);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from cache.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $key=$this->calculateKey($timestamp);
- if(($data=$this->getCache()->get($key))!==false)
- return $data;
- }
- throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
- }
-}
-
+<?php +/** + * TCachePageStatePersister class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TCachePageStatePersister class + * + * TCachePageStatePersister implements a page state persistent method based on cache. + * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token + * is passed to the client side to identify the state. This greatly reduces the size of + * the page state that needs to be transmitted between the server and the client. Of course, + * this is at the cost of using server side resource. + * + * A cache module has to be loaded in order to use TCachePageStatePersister. + * By default, TCachePageStatePersister will use the primary cache module. + * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}. + * Any cache module, as long as it implements the interface {@link ICache}, may be used. + * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc. + * + * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data + * that stores in cache. + * + * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister + * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}. + * + * There are a couple of ways to use TCachePageStatePersister. + * One can override the page's {@link TPage::getStatePersister()} method and + * create a TCachePageStatePersister instance there. + * Or one can configure the pages to use TCachePageStatePersister in page configurations + * as follows, + * <code> + * <pages StatePersisterClass="System.Web.UI.TCachePageStatePersister" + * StatePersister.CacheModuleID="mycache" + * StatePersister.CacheTimeout="3600" /> + * </code> + * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID + * for the TCachePageStatePersister instance. + * + * The above configuration will affect the pages under the directory containing + * this configuration and all its subdirectories. + * To configure individual pages to use TCachePageStatePersister, use + * <code> + * <pages> + * <page id="PageID" StatePersisterClass="System.Web.UI.TCachePageStatePersister" /> + * </pages> + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.1.1 + */ +class TCachePageStatePersister extends TComponent implements IPageStatePersister +{ + private $_prefix='statepersister'; + private $_page; + private $_cache=null; + private $_cacheModuleID=''; + private $_timeout=1800; + + /** + * @param TPage the page that this persister works for + */ + public function getPage() + { + return $this->_page; + } + + /** + * @param TPage the page that this persister works for. + */ + public function setPage(TPage $page) + { + $this->_page=$page; + } + + /** + * @return string the ID of the cache module. + */ + public function getCacheModuleID() + { + return $this->_cacheModuleID; + } + + /** + * @param string the ID of the cache module. If not set, the primary cache module will be used. + */ + public function setCacheModuleID($value) + { + $this->_cacheModuleID=$value; + } + + /** + * @return ICache the cache module being used for data storage + */ + public function getCache() + { + if($this->_cache===null) + { + if($this->_cacheModuleID!=='') + $cache=Prado::getApplication()->getModule($this->_cacheModuleID); + else + $cache=Prado::getApplication()->getCache(); + if($cache===null || !($cache instanceof ICache)) + { + if($this->_cacheModuleID!=='') + throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID); + else + throw new TConfigurationException('cachepagestatepersister_cache_required'); + } + $this->_cache=$cache; + } + return $this->_cache; + } + + /** + * @return integer the number of seconds in which the cached state will expire. Defaults to 1800. + */ + public function getCacheTimeout() + { + return $this->_timeout; + } + + /** + * @param integer the number of seconds in which the cached state will expire. 0 means never expire. + * @throws TInvalidDataValueException if the number is smaller than 0. + */ + public function setCacheTimeout($value) + { + if(($value=TPropertyValue::ensureInteger($value))>=0) + $this->_timeout=$value; + else + throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid'); + } + + /** + * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'. + */ + public function getKeyPrefix() + { + return $this->_prefix; + } + + /** + * @param string prefix of cache variable name to avoid conflict with other cache data + */ + public function setKeyPrefix($value) + { + $this->_prefix=$value; + } + + /** + * @param string micro timestamp when saving state occurs + * @return string a key that is unique per user request + */ + protected function calculateKey($timestamp) + { + return $this->getKeyPrefix().':' + . $this->_page->getRequest()->getUserHostAddress() + . $this->_page->getPagePath() + . $timestamp; + } + + /** + * Saves state in cache. + * @param mixed state to be stored + */ + public function save($data) + { + $timestamp=(string)microtime(true); + $key=$this->calculateKey($timestamp); + $this->getCache()->add($key,$data,$this->_timeout); + $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp)); + } + + /** + * Loads page state from cache. + * @return mixed the restored state + * @throws THttpException if page state is corrupted + */ + public function load() + { + if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null) + { + $key=$this->calculateKey($timestamp); + if(($data=$this->getCache()->get($key))!==false) + return $data; + } + throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted'); + } +} + diff --git a/framework/Web/UI/TCompositeControl.php b/framework/Web/UI/TCompositeControl.php index 285a8129..e7766ab8 100644 --- a/framework/Web/UI/TCompositeControl.php +++ b/framework/Web/UI/TCompositeControl.php @@ -1,38 +1,38 @@ -<?php
-/**
- * TCompositeControl class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TCompositeControl class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCompositeControl class.
- * TCompositeControl is the base class for controls that are composed
- * by other controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeControl extends TControl implements INamingContainer
-{
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TCompositeControl class. + * TCompositeControl is the base class for controls that are composed + * by other controls. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TCompositeControl extends TControl implements INamingContainer +{ + /** + * Performs the OnInit step for the control and all its child controls. + * This method overrides the parent implementation + * by ensuring child controls are created first. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + parent::initRecursive($namingContainer); + } +} + diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php index 316098a1..2adabb55 100644 --- a/framework/Web/UI/TControl.php +++ b/framework/Web/UI/TControl.php @@ -1,2395 +1,2395 @@ -<?php
-/**
- * TControl, TControlCollection, TEventParameter and INamingContainer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TAttributeCollection and TControlAdapter class
- */
-Prado::using('System.Collections.TAttributeCollection');
-Prado::using('System.Web.UI.TControlAdapter');
-
-/**
- * TControl class
- *
- * TControl is the base class for all components on a page hierarchy.
- * It implements the following features for UI-related functionalities:
- * - databinding feature
- * - parent and child relationship
- * - naming container and containee relationship
- * - viewstate and controlstate features
- * - rendering scheme
- * - control lifecycles
- *
- * A property can be data-bound with an expression. By calling {@link dataBind},
- * expressions bound to properties will be evaluated and the results will be
- * set to the corresponding properties.
- *
- * Parent and child relationship determines how the presentation of controls are
- * enclosed within each other. A parent will determine where to place
- * the presentation of its child controls. For example, a TPanel will enclose
- * all its child controls' presentation within a div html tag. A control's parent
- * can be obtained via {@link getParent Parent} property, and its
- * {@link getControls Controls} property returns a list of the control's children,
- * including controls and static texts. The property can be manipulated
- * like an array for adding or removing a child (see {@link TList} for more details).
- *
- * A naming container control implements INamingContainer and ensures that
- * its containee controls can be differentiated by their ID property values.
- * Naming container and containee realtionship specifies a protocol to uniquely
- * identify an arbitrary control on a page hierarchy by an ID path (concatenation
- * of all naming containers' IDs and the target control's ID).
- *
- * Viewstate and controlstate are two approaches to preserve state across
- * page postback requests. ViewState is mainly related with UI specific state
- * and can be disabled if not needed. ControlState represents crucial logic state
- * and cannot be disabled.
- *
- * A control is rendered via its {@link render()} method (the method is invoked
- * by the framework.) Descendant control classes may override this method for
- * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
- * which is responsible for rendering of children of the control.
- * Control's {@link getVisible Visible} property governs whether the control
- * should be rendered or not.
- *
- * Each control on a page will undergo a series of lifecycles, including
- * control construction, Init, Load, PreRender, Render, and OnUnload.
- * They work together with page lifecycles to process a page request.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControl extends TApplicationComponent implements IRenderable, IBindable
-{
- /**
- * format of control ID
- */
- const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
- /**
- * separator char between IDs in a UniqueID
- */
- const ID_SEPARATOR='$';
- /**
- * separator char between IDs in a ClientID
- */
- const CLIENT_ID_SEPARATOR='_';
- /**
- * prefix to an ID automatically generated
- */
- const AUTOMATIC_ID_PREFIX='ctl';
-
- /**
- * the stage of lifecycles that the control is currently at
- */
- const CS_CONSTRUCTED=0;
- const CS_CHILD_INITIALIZED=1;
- const CS_INITIALIZED=2;
- const CS_STATE_LOADED=3;
- const CS_LOADED=4;
- const CS_PRERENDERED=5;
-
- /**
- * State bits.
- */
- const IS_ID_SET=0x01;
- const IS_DISABLE_VIEWSTATE=0x02;
- const IS_SKIN_APPLIED=0x04;
- const IS_STYLESHEET_APPLIED=0x08;
- const IS_DISABLE_THEMING=0x10;
- const IS_CHILD_CREATED=0x20;
- const IS_CREATING_CHILD=0x40;
-
- /**
- * Indexes for the rare fields.
- * In order to save memory, rare fields will only be created if they are needed.
- */
- const RF_CONTROLS=0; // child controls
- const RF_CHILD_STATE=1; // child state field
- const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
- const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
- const RF_SKIN_ID=4; // skin ID
- const RF_DATA_BINDINGS=5; // data bindings
- const RF_EVENTS=6; // event handlers
- const RF_CONTROLSTATE=7; // controlstate
- const RF_NAMED_OBJECTS=8; // controls declared with ID on template
- const RF_ADAPTER=9; // adapter
- const RF_AUTO_BINDINGS=10; // auto data bindings
-
- /**
- * @var string control ID
- */
- private $_id='';
- /**
- * @var string control unique ID
- */
- private $_uid;
- /**
- * @var TControl parent of the control
- */
- private $_parent;
- /**
- * @var TPage page that the control resides in
- */
- private $_page;
- /**
- * @var TControl naming container of the control
- */
- private $_namingContainer;
- /**
- * @var TTemplateControl control whose template contains the control
- */
- private $_tplControl;
- /**
- * @var array viewstate data
- */
- private $_viewState=array();
- /**
- * @var array temporary state (usually set in template)
- */
- private $_tempState=array();
- /**
- * @var boolean whether we should keep state in viewstate
- */
- private $_trackViewState=true;
- /**
- * @var integer the current stage of the control lifecycles
- */
- private $_stage=0;
- /**
- * @var integer representation of the state bits
- */
- private $_flags=0;
- /**
- * @var array a collection of rare control data
- */
- private $_rf=array();
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- }
-
- /**
- * Returns a property value by name or a control by ID.
- * This overrides the parent implementation by allowing accessing
- * a control via its ID using the following syntax,
- * <code>
- * $menuBar=$this->menuBar;
- * </code>
- * Note, the control must be configured in the template
- * with explicit ID. If the name matches both a property and a control ID,
- * the control ID will take the precedence.
- *
- * @param string the property name or control ID
- * @return mixed the property value or the target control
- * @throws TInvalidOperationException if the property is not defined.
- * @see registerObject
- */
- public function __get($name)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- return $this->_rf[self::RF_NAMED_OBJECTS][$name];
- else
- return parent::__get($name);
- }
-
- /**
- * @return boolean whether there is an adapter for this control
- */
- public function getHasAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER]);
- }
-
- /**
- * @return TControlAdapter control adapter. Null if not exists.
- */
- public function getAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
- }
-
- /**
- * @param TControlAdapter control adapter
- */
- public function setAdapter(TControlAdapter $adapter)
- {
- $this->_rf[self::RF_ADAPTER]=$adapter;
- }
-
- /**
- * @return TControl the parent of this control
- */
- public function getParent()
- {
- return $this->_parent;
- }
-
- /**
- * @return TControl the naming container of this control
- */
- public function getNamingContainer()
- {
- if(!$this->_namingContainer && $this->_parent)
- {
- if($this->_parent instanceof INamingContainer)
- $this->_namingContainer=$this->_parent;
- else
- $this->_namingContainer=$this->_parent->getNamingContainer();
- }
- return $this->_namingContainer;
- }
-
- /**
- * @return TPage the page that contains this control
- */
- public function getPage()
- {
- if(!$this->_page)
- {
- if($this->_parent)
- $this->_page=$this->_parent->getPage();
- else if($this->_tplControl)
- $this->_page=$this->_tplControl->getPage();
- }
- return $this->_page;
- }
-
- /**
- * Sets the page for a control.
- * Only framework developers should use this method.
- * @param TPage the page that contains this control
- */
- public function setPage($page)
- {
- $this->_page=$page;
- }
-
- /**
- * Sets the control whose template contains this control.
- * Only framework developers should use this method.
- * @param TTemplateControl the control whose template contains this control
- */
- public function setTemplateControl($control)
- {
- $this->_tplControl=$control;
- }
-
- /**
- * @return TTemplateControl the control whose template contains this control
- */
- public function getTemplateControl()
- {
- if(!$this->_tplControl && $this->_parent)
- $this->_tplControl=$this->_parent->getTemplateControl();
- return $this->_tplControl;
- }
-
- /**
- * @return TTemplateControl the control whose template is loaded from
- * some external storage, such as file, db, and whose template ultimately
- * contains this control.
- */
- public function getSourceTemplateControl()
- {
- $control=$this;
- while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
- {
- if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
- return $control;
- }
- return $this->getPage();
- }
-
- /**
- * Gets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @return integer the lifecycle step the control is currently at.
- * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function getControlStage()
- {
- return $this->_stage;
- }
-
- /**
- * Sets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @param integer the lifecycle step the control is currently at.
- * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function setControlStage($value)
- {
- $this->_stage=$value;
- }
-
- /**
- * Returns the id of the control.
- * Control ID can be either manually set or automatically generated.
- * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
- * @param boolean whether to hide automatically generated ID
- * @return string the ID of the control
- */
- public function getID($hideAutoID=true)
- {
- if($hideAutoID)
- return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
- else
- return $this->_id;
- }
-
- /**
- * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
- * @throws TInvalidDataValueException if ID is in a bad format
- */
- public function setID($id)
- {
- if(!preg_match(self::ID_FORMAT,$id))
- throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
- $this->_id=$id;
- $this->_flags |= self::IS_ID_SET;
- $this->clearCachedUniqueID($this instanceof INamingContainer);
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Returns a unique ID that identifies the control in the page hierarchy.
- * A unique ID is the contenation of all naming container controls' IDs and the control ID.
- * These IDs are separated by '$' character.
- * Control users should not rely on the specific format of UniqueID, however.
- * @return string a unique ID that identifies the control in the page hierarchy
- */
- public function getUniqueID()
- {
- if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
- {
- $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
- if($namingContainer=$this->getNamingContainer())
- {
- if($this->getPage()===$namingContainer)
- return ($this->_uid=$this->_id);
- else if(($prefix=$namingContainer->getUniqueID())==='')
- return $this->_id;
- else
- return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
- }
- else // no naming container
- return $this->_id;
- }
- else
- return $this->_uid;
- }
-
- /**
- * Sets input focus to this control.
- */
- public function focus()
- {
- $this->getPage()->setFocus($this);
- }
-
- /**
- * Returns the client ID of the control.
- * The client ID can be used to uniquely identify
- * the control in client-side scripts (such as JavaScript).
- * Do not rely on the explicit format of the return ID.
- * @return string the client ID of the control
- */
- public function getClientID()
- {
- return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * Converts a unique ID to a client ID.
- * @param string the unique ID of a control
- * @return string the client ID of the control
- */
- public static function convertUniqueIdToClientId($uniqueID)
- {
- return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * @return string the skin ID of this control, '' if not set
- */
- public function getSkinID()
- {
- return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function setSkinID($value)
- {
- if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
- else
- $this->_rf[self::RF_SKIN_ID]=$value;
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function getIsSkinApplied()
- {
- return ($this->_flags & self::IS_SKIN_APPLIED);
- }
-
- /**
- * @return boolean whether theming is enabled for this control.
- * The theming is enabled if the control and all its parents have it enabled.
- */
- public function getEnableTheming()
- {
- if($this->_flags & self::IS_DISABLE_THEMING)
- return false;
- else
- return $this->_parent?$this->_parent->getEnableTheming():true;
- }
-
- /**
- * @param boolean whether to enable theming
- * @throws TInvalidOperationException if this method is invoked after OnPreInit
- */
- public function setEnableTheming($value)
- {
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
- else if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_THEMING;
- else
- $this->_flags |= self::IS_DISABLE_THEMING;
- }
-
- /**
- * Returns custom data associated with this control.
- * A control may be associated with some custom data for various purposes.
- * For example, a button may be associated with a string to identify itself
- * in a generic OnClick event handler.
- * @return mixed custom data associated with this control. Defaults to null.
- */
- public function getCustomData()
- {
- return $this->getViewState('CustomData',null);
- }
-
- /**
- * Associates custom data with this control.
- * Note, the custom data must be serializable and unserializable.
- * @param mixed custom data
- */
- public function setCustomData($value)
- {
- $this->setViewState('CustomData',$value,null);
- }
-
- /**
- * @return boolean whether the control has child controls
- */
- public function getHasControls()
- {
- return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
- }
-
- /**
- * @return TControlCollection the child control collection
- */
- public function getControls()
- {
- if(!isset($this->_rf[self::RF_CONTROLS]))
- $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
- return $this->_rf[self::RF_CONTROLS];
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TControlCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
- }
-
- /**
- * Checks if a control is visible.
- * If parent check is required, then a control is visible only if the control
- * and all its ancestors are visible.
- * @param boolean whether the parents should also be checked if visible
- * @return boolean whether the control is visible (default=true).
- */
- public function getVisible($checkParents=true)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getVisible(false))
- return false;
- return true;
- }
- else
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the control is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a value indicating whether the control is enabled.
- * A control is enabled if it allows client user interaction.
- * If $checkParents is true, all parent controls will be checked,
- * and unless they are all enabled, false will be returned.
- * The property Enabled is mainly used for {@link TWebControl}
- * derived controls.
- * @param boolean whether the parents should also be checked enabled
- * @return boolean whether the control is enabled.
- */
- public function getEnabled($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getViewState('Enabled',true))
- return false;
- return true;
- }
- else
- return $this->getViewState('Enabled',true);
- }
-
- /**
- * @param boolean whether the control is to be enabled.
- */
- public function setEnabled($value)
- {
- $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the control has custom attributes
- */
- public function getHasAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->getCount()>0;
- else
- return false;
- }
-
- /**
- * Returns the list of custom attributes.
- * Custom attributes are name-value pairs that may be rendered
- * as HTML tags' attributes.
- * @return TAttributeCollection the list of custom attributes
- */
- public function getAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('Attributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->contains($name);
- else
- return false;
- }
-
- /**
- * @return string attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->itemAt($name);
- else
- return null;
- }
-
- /**
- * Sets a custom control attribute.
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, null if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->remove($name);
- else
- return null;
- }
-
- /**
- * @return boolean whether viewstate is enabled
- */
- public function getEnableViewState($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control!==null;$control=$control->getParent())
- if($control->_flags & self::IS_DISABLE_VIEWSTATE)
- return false;
- return true;
- }
- else
- return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
- }
-
- /**
- * @param boolean set whether to enable viewstate
- */
- public function setEnableViewState($value)
- {
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
- else
- $this->_flags |= self::IS_DISABLE_VIEWSTATE;
- }
-
- /**
- * Returns a controlstate value.
- *
- * This function is mainly used in defining getter functions for control properties
- * that must be kept in controlstate.
- * @param string the name of the controlstate value to be returned
- * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
- * @return mixed the controlstate value corresponding to $key
- */
- protected function getControlState($key,$defaultValue=null)
- {
- return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
- }
-
- /**
- * Sets a controlstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in controlstate.
- * Make sure that the controlstate value must be serializable and unserializable.
- * @param string the name of the controlstate value
- * @param mixed the controlstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
- */
- protected function setControlState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- else
- $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
- }
-
- /**
- * Clears a controlstate value.
- * @param string the name of the controlstate value to be cleared
- */
- protected function clearControlState($key)
- {
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- }
-
- /**
- * Sets a value indicating whether we should keep data in viewstate.
- * When it is false, data saved via setViewState() will not be persisted.
- * By default, it is true, meaning data will be persisted across postbacks.
- * @param boolean whether data should be persisted
- */
- public function trackViewState($enabled)
- {
- $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
- }
-
- /**
- * Returns a viewstate value.
- *
- * This function is very useful in defining getter functions for component properties
- * that must be kept in viewstate.
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- public function getViewState($key,$defaultValue=null)
- {
- if(isset($this->_viewState[$key]))
- return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
- else if(isset($this->_tempState[$key]))
- {
- if(is_object($this->_tempState[$key]) && $this->_trackViewState)
- $this->_viewState[$key]=$this->_tempState[$key];
- return $this->_tempState[$key];
- }
- else
- return $defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in viewstate.
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- public function setViewState($key,$value,$defaultValue=null)
- {
- if($this->_trackViewState)
- {
- $this->_viewState[$key]=$value;
- unset($this->_tempState[$key]);
- }
- else
- {
- unset($this->_viewState[$key]);
- $this->_tempState[$key]=$value;
- }
- }
-
- /**
- * Clears a viewstate value.
- * @param string the name of the viewstate value to be cleared
- */
- public function clearViewState($key)
- {
- unset($this->_viewState[$key]);
- unset($this->_tempState[$key]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function bindProperty($name,$expression)
- {
- $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
- }
-
- /**
- * Breaks the binding between a property (or property path) and an expression.
- * @param string the property name (or property path)
- */
- public function unbindProperty($name)
- {
- unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * Unlike regular databinding, the expression bound by this method
- * is automatically evaluated during {@link prerenderRecursive()}.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function autoBindProperty($name,$expression)
- {
- $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
- }
-
- /**
- * Performs the databinding for this control.
- */
- public function dataBind()
- {
- $this->dataBindProperties();
- $this->onDataBinding(null);
- $this->dataBindChildren();
- }
-
- /**
- * Databinding properties of the control.
- */
- protected function dataBindProperties()
- {
- Prado::trace("Data bind properties",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_DATA_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Auto databinding properties of the control.
- */
- protected function autoDataBindProperties()
- {
- if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Databinding child controls.
- */
- protected function dataBindChildren()
- {
- Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof IBindable)
- $control->dataBind();
- }
- }
-
- /**
- * @return boolean whether child controls have been created
- */
- final protected function getChildControlsCreated()
- {
- return ($this->_flags & self::IS_CHILD_CREATED)!==0;
- }
-
- /**
- * Sets a value indicating whether child controls are created.
- * If false, any existing child controls will be cleared up.
- * @param boolean whether child controls are created
- */
- final protected function setChildControlsCreated($value)
- {
- if($value)
- $this->_flags |= self::IS_CHILD_CREATED;
- else
- {
- if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
- $this->getControls()->clear();
- $this->_flags &= ~self::IS_CHILD_CREATED;
- }
- }
-
- /**
- * Ensures child controls are created.
- * If child controls are not created yet, this method will invoke
- * {@link createChildControls} to create them.
- */
- public function ensureChildControls()
- {
- if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
- {
- try
- {
- $this->_flags |= self::IS_CREATING_CHILD;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->createChildControls();
- else
- $this->createChildControls();
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- }
- catch(Exception $e)
- {
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- throw $e;
- }
- }
- }
-
- /**
- * Creates child controls.
- * This method can be overriden for controls who want to have their controls.
- * Do not call this method directly. Instead, call {@link ensureChildControls}
- * to ensure child controls are created only once.
- */
- public function createChildControls()
- {
- }
-
- /**
- * Finds a control by ID path within the current naming container.
- * The current naming container is either the control itself
- * if it implements {@link INamingContainer} or the control's naming container.
- * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
- * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
- * whose naming container is 'Item1' whose naming container is 'Repeater1'.
- * @param string ID of the control to be looked up
- * @return TControl|null the control found, null if not found
- * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
- */
- public function findControl($id)
- {
- $id=strtr($id,'.',self::ID_SEPARATOR);
- $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
- if(!$container || !$container->getHasControls())
- return null;
- if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
- {
- $container->_rf[self::RF_NAMED_CONTROLS]=array();
- $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
- }
- if(($pos=strpos($id,self::ID_SEPARATOR))===false)
- return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
- else
- {
- $cid=substr($id,0,$pos);
- $sid=substr($id,$pos+1);
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
- return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
- else
- return null;
- }
- }
-
- /**
- * Finds all child and grand-child controls that are of the specified type.
- * @param string the class name
- * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
- * @return array list of controls found
- */
- public function findControlsByType($type,$strict=true)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
- $controls[]=$control;
- if(($control instanceof TControl) && $control->getHasControls())
- $controls=array_merge($controls,$control->findControlsByType($type,$strict));
- }
- }
- return $controls;
- }
-
- /**
- * Finds all child and grand-child controls with the specified ID.
- * Note, this method is different from {@link findControl} in that
- * it searches through all controls that have this control as the ancestor
- * while {@link findcontrol} only searches through controls that have this
- * control as the direct naming container.
- * @param string the ID being looked for
- * @return array list of controls found
- */
- public function findControlsByID($id)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id===$id)
- $controls[]=$control;
- $controls=array_merge($controls,$control->findControlsByID($id));
- }
- }
- }
- return $controls;
- }
-
- /**
- * Resets the control as a naming container.
- * Only framework developers should use this method.
- */
- public function clearNamingContainer()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
- $this->clearNameTable();
- }
-
- /**
- * Registers an object by a name.
- * A registered object can be accessed like a public member variable.
- * This method should only be used by framework and control developers.
- * @param string name of the object
- * @param object object to be declared
- * @see __get
- */
- public function registerObject($name,$object)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- throw new TInvalidOperationException('control_object_reregistered',$name);
- $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
- }
-
- /**
- * Unregisters an object by name.
- * @param string name of the object
- * @see registerObject
- */
- public function unregisterObject($name)
- {
- unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean whether an object has been registered with the name
- * @see registerObject
- */
- public function isObjectRegistered($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean true if the child control has been initialized.
- */
- public function getHasChildInitialized()
- {
- return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
- }
-
- /**
- * @return boolean true if the onInit event has raised.
- */
- public function getHasInitialized()
- {
- return $this->getControlStage() >= self::CS_INITIALIZED;
- }
-
- /**
- * @return boolean true if the control has loaded post data.
- */
- public function getHasLoadedPostData()
- {
- return $this->getControlStage() >= self::CS_STATE_LOADED;
- }
-
- /**
- * @return boolean true if the onLoad event has raised.
- */
- public function getHasLoaded()
- {
- return $this->getControlStage() >= self::CS_LOADED;
- }
-
- /**
- * @return boolean true if onPreRender event has raised.
- */
- public function getHasPreRendered()
- {
- return $this->getControlStage() >= self::CS_PRERENDERED;
- }
-
- /**
- * Returns the named registered object.
- * A component with explicit ID on a template will be registered to
- * the template owner. This method allows you to obtain this component
- * with the ID.
- * @return mixed the named registered object. Null if object is not found.
- */
- public function getRegisteredObject($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
- }
-
- /**
- * @return boolean whether body contents are allowed for this control. Defaults to true.
- */
- public function getAllowChildControls()
- {
- return true;
- }
-
- /**
- * Adds the object instantiated on a template to the child control collection.
- * This method overrides the parent implementation.
- * Only framework developers and control developers should use this method.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- $this->getControls()->add($object);
- }
-
- /**
- * Clears up the child state data.
- * After a control loads its state, those state that do not belong to
- * any existing child controls are stored as child state.
- * This method will remove these state.
- * Only frameworker developers and control developers should use this method.
- */
- final protected function clearChildState()
- {
- unset($this->_rf[self::RF_CHILD_STATE]);
- }
-
- /**
- * @param TControl the potential ancestor control
- * @return boolean if the control is a descendent (parent, parent of parent, etc.)
- * of the specified control
- */
- final protected function isDescendentOf($ancestor)
- {
- $control=$this;
- while($control!==$ancestor && $control->_parent)
- $control=$control->_parent;
- return $control===$ancestor;
- }
-
- /**
- * Adds a control into the child collection of the control.
- * Control lifecycles will be caught up during the addition.
- * Only framework developers should use this method.
- * @param TControl the new child control
- */
- public function addedControl($control)
- {
- if($control->_parent)
- $control->_parent->getControls()->remove($control);
- $control->_parent=$this;
- $control->_page=$this->getPage();
- $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
- if($namingContainer)
- {
- $control->_namingContainer=$namingContainer;
- if($control->_id==='')
- $control->generateAutomaticID();
- else
- $namingContainer->clearNameTable();
- $control->clearCachedUniqueID($control instanceof INamingContainer);
- }
-
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- {
- $control->initRecursive($namingContainer);
- if($this->_stage>=self::CS_STATE_LOADED)
- {
- if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
- {
- $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
- unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
- }
- else
- $state=null;
- $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if($this->_stage>=self::CS_LOADED)
- {
- $control->loadRecursive();
- if($this->_stage>=self::CS_PRERENDERED)
- $control->preRenderRecursive();
- }
- }
- }
- }
-
- /**
- * Removes a control from the child collection of the control.
- * Only framework developers should use this method.
- * @param TControl the child control removed
- */
- public function removedControl($control)
- {
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- $control->unloadRecursive();
- $control->_parent=null;
- $control->_page=null;
- $control->_namingContainer=null;
- $control->_tplControl=null;
- //$control->_stage=self::CS_CONSTRUCTED;
- if(!($control->_flags & self::IS_ID_SET))
- $control->_id='';
- else
- unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
- $control->clearCachedUniqueID(true);
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->getHasControls())
- {
- if($this instanceof INamingContainer)
- $namingContainer=$this;
- $page=$this->getPage();
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->_namingContainer=$namingContainer;
- $control->_page=$page;
- if($control->_id==='' && $namingContainer)
- $control->generateAutomaticID();
- $control->initRecursive($namingContainer);
- }
- }
- }
- if($this->_stage<self::CS_INITIALIZED)
- {
- $this->_stage=self::CS_CHILD_INITIALIZED;
- if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
- {
- $page->applyControlSkin($this);
- $this->_flags |= self::IS_SKIN_APPLIED;
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onInit(null);
- else
- $this->onInit(null);
- $this->_stage=self::CS_INITIALIZED;
- }
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function loadRecursive()
- {
- if($this->_stage<self::CS_LOADED)
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onLoad(null);
- else
- $this->onLoad(null);
- }
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->loadRecursive();
- }
- }
- if($this->_stage<self::CS_LOADED)
- $this->_stage=self::CS_LOADED;
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function preRenderRecursive()
- {
- $this->autoDataBindProperties();
-
- if($this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onPreRender(null);
- else
- $this->onPreRender(null);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->preRenderRecursive();
- else if($control instanceof TCompositeLiteral)
- $control->evaluateDynamicContent();
- }
- }
- $this->addToPostDataLoader();
- }
- $this->_stage=self::CS_PRERENDERED;
- }
-
- /**
- * Add controls implementing IPostBackDataHandler to post data loaders.
- */
- protected function addToPostDataLoader()
- {
- if($this instanceof IPostBackDataHandler)
- $this->getPage()->registerPostDataLoader($this);
- }
-
- /**
- * Performs the Unload step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function unloadRecursive()
- {
- if(!($this->_flags & self::IS_ID_SET))
- $this->_id='';
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->unloadRecursive();
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onUnload(null);
- else
- $this->onUnload(null);
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * The method raises 'OnInit' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->raiseEvent('OnInit',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * The method raises 'OnLoad' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->raiseEvent('OnLoad',$this,$param);
- }
-
- /**
- * Raises 'OnDataBinding' event.
- * This method is invoked when {@link dataBind} is invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onDataBinding($param)
- {
- Prado::trace("onDataBinding()",'System.Web.UI.TControl');
- $this->raiseEvent('OnDataBinding',$this,$param);
- }
-
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * The method raises 'OnUnload' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->raiseEvent('OnUnload',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * The method raises 'OnPreRender' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->raiseEvent('OnPreRender',$this,$param);
- }
-
- /**
- * Invokes the parent's bubbleEvent method.
- * A control who wants to bubble an event must call this method in its onEvent method.
- * @param TControl sender of the event
- * @param TEventParameter event parameter
- * @see bubbleEvent
- */
- protected function raiseBubbleEvent($sender,$param)
- {
- $control=$this;
- while($control=$control->_parent)
- {
- if($control->bubbleEvent($sender,$param))
- break;
- }
- }
-
- /**
- * This method responds to a bubbled event.
- * This method should be overriden to provide customized response to a bubbled event.
- * Check the type of event parameter to determine what event is bubbled currently.
- * @param TControl sender of the event
- * @param TEventParameter event parameters
- * @return boolean true if the event bubbling is handled and no more bubbling.
- * @see raiseBubbleEvent
- */
- public function bubbleEvent($sender,$param)
- {
- return false;
- }
-
- /**
- * Broadcasts an event.
- * The event will be sent to all controls on the current page hierarchy.
- * If a control defines the event, the event will be raised for the control.
- * If a control implements {@link IBroadcastEventReceiver}, its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
- * be invoked which gives the control a chance to respond to the event.
- * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
- * event will have this event raised, and all controls implementing
- * {@link IBroadcastEventReceiver} will also have its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
- * invoked.
- * @param string name of the broadcast event
- * @param TControl sender of this event
- * @param TEventParameter event parameter
- */
- public function broadcastEvent($name,$sender,$param)
- {
- $rootControl=(($page=$this->getPage())===null)?$this:$page;
- $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
- }
-
- /**
- * Recursively broadcasts an event.
- * This method should only be used by framework developers.
- * @param string name of the broadcast event
- * @param TControl sender of the event
- * @param TBroadcastEventParameter event parameter
- */
- private function broadcastEventInternal($name,$sender,$param)
- {
- if($this->hasEvent($name))
- $this->raiseEvent($name,$sender,$param->getParameter());
- if($this instanceof IBroadcastEventReceiver)
- $this->broadcastEventReceived($sender,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->broadcastEventInternal($name,$sender,$param);
- }
- }
- }
-
- /**
- * Traverse the whole control hierarchy rooted at this control.
- * Callback function may be invoked for each control being visited.
- * A pre-callback is invoked before traversing child controls;
- * A post-callback is invoked after traversing child controls.
- * Callback functions can be global functions or class methods.
- * They must be of the following signature:
- * <code>
- * function callback_func($control,$param) {...}
- * </code>
- * where $control refers to the control being visited and $param
- * is the parameter that is passed originally when calling this traverse function.
- *
- * @param mixed parameter to be passed to callbacks for each control
- * @param callback callback invoked before traversing child controls. If null, it is ignored.
- * @param callback callback invoked after traversing child controls. If null, it is ignored.
- */
- protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
- {
- if($preCallback!==null)
- call_user_func($preCallback,$this,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->traverseChildControls($param,$preCallback,$postCallback);
- }
- }
- }
- if($postCallback!==null)
- call_user_func($postCallback,$this,$param);
- }
-
- /**
- * Renders the control.
- * Only when the control is visible will the control be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderControl($writer)
- {
- if($this instanceof IActiveControl || $this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->render($writer);
- else
- $this->render($writer);
- }
- }
-
- /**
- * Renders the control.
- * This method is invoked by {@link renderControl} when the control is visible.
- * You can override this method to provide customized rendering of the control.
- * By default, the control simply renders all its child contents.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $this->renderChildren($writer);
- }
-
- /**
- * Renders the children of the control.
- * This method iterates through all child controls and static text strings
- * and renders them in order.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderChildren($writer)
- {
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_string($control))
- $writer->write($control);
- else if($control instanceof TControl)
- $control->renderControl($writer);
- else if($control instanceof IRenderable)
- $control->render($writer);
- }
- }
- }
-
- /**
- * 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()
- {
- }
-
- /**
- * 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()
- {
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- if(is_array($state))
- {
- // A null state means the stateful properties all take default values.
- // So if the state is enabled, we have to assign the null value.
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if(isset($state[1]))
- {
- $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
- unset($state[1]);
- }
- else
- unset($this->_rf[self::RF_CONTROLSTATE]);
- if($needViewState)
- {
- if(isset($state[0]))
- $this->_viewState=&$state[0];
- else
- $this->_viewState=array();
- }
- unset($state[0]);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if(isset($state[$control->_id]))
- {
- $control->loadStateRecursive($state[$control->_id],$needViewState);
- unset($state[$control->_id]);
- }
- }
- }
- }
- if(!empty($state))
- $this->_rf[self::RF_CHILD_STATE]=&$state;
- }
- $this->_stage=self::CS_STATE_LOADED;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->loadState();
- else
- $this->loadState();
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->saveState();
- else
- $this->saveState();
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- $state=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $state[$control->_id]=&$control->saveStateRecursive($needViewState);
- }
- }
- if($needViewState && !empty($this->_viewState))
- $state[0]=&$this->_viewState;
- if(isset($this->_rf[self::RF_CONTROLSTATE]))
- $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
- return $state;
- }
-
- /**
- * Applies a stylesheet skin to a control.
- * @param TPage the page containing the control
- * @throws TInvalidOperationException if the stylesheet skin is applied already
- */
- public function applyStyleSheetSkin($page)
- {
- if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
- {
- $page->applyControlStyleSheet($this);
- $this->_flags |= self::IS_STYLESHEET_APPLIED;
- }
- else if($this->_flags & self::IS_STYLESHEET_APPLIED)
- throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
- }
-
- /**
- * Clears the cached UniqueID.
- * If $recursive=true, all children's cached UniqueID will be cleared as well.
- * @param boolean whether the clearing is recursive.
- */
- private function clearCachedUniqueID($recursive)
- {
- if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->clearCachedUniqueID($recursive);
- }
- $this->_uid=null;
- }
-
- /**
- * Generates an automatic ID for the control.
- */
- private function generateAutomaticID()
- {
- $this->_flags &= ~self::IS_ID_SET;
- if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
- $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
- $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
- $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Clears the list of the controls whose IDs are managed by the specified naming container.
- */
- private function clearNameTable()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS]);
- }
-
- /**
- * Updates the list of the controls whose IDs are managed by the specified naming container.
- * @param TControl the naming container
- * @param TControlCollection list of controls
- * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
- */
- private function fillNameTable($container,$controls)
- {
- foreach($controls as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id!=='')
- {
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
- throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
- else
- $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
- }
- if(!($control instanceof INamingContainer) && $control->getHasControls())
- $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
- }
- }
- }
-}
-
-
-/**
- * TControlCollection class
- *
- * TControlCollection implements a collection that enables
- * controls to maintain a list of their child controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <b>OnClick</b> event.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param);
-
- /**
- * Raises <b>OnCommand</b> 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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <b>Command</b>
- * 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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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));
- }
-}
-
-?>
+<?php +/** + * TControl, TControlCollection, TEventParameter and INamingContainer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * Includes TAttributeCollection and TControlAdapter class + */ +Prado::using('System.Collections.TAttributeCollection'); +Prado::using('System.Web.UI.TControlAdapter'); + +/** + * TControl class + * + * TControl is the base class for all components on a page hierarchy. + * It implements the following features for UI-related functionalities: + * - databinding feature + * - parent and child relationship + * - naming container and containee relationship + * - viewstate and controlstate features + * - rendering scheme + * - control lifecycles + * + * A property can be data-bound with an expression. By calling {@link dataBind}, + * expressions bound to properties will be evaluated and the results will be + * set to the corresponding properties. + * + * Parent and child relationship determines how the presentation of controls are + * enclosed within each other. A parent will determine where to place + * the presentation of its child controls. For example, a TPanel will enclose + * all its child controls' presentation within a div html tag. A control's parent + * can be obtained via {@link getParent Parent} property, and its + * {@link getControls Controls} property returns a list of the control's children, + * including controls and static texts. The property can be manipulated + * like an array for adding or removing a child (see {@link TList} for more details). + * + * A naming container control implements INamingContainer and ensures that + * its containee controls can be differentiated by their ID property values. + * Naming container and containee realtionship specifies a protocol to uniquely + * identify an arbitrary control on a page hierarchy by an ID path (concatenation + * of all naming containers' IDs and the target control's ID). + * + * Viewstate and controlstate are two approaches to preserve state across + * page postback requests. ViewState is mainly related with UI specific state + * and can be disabled if not needed. ControlState represents crucial logic state + * and cannot be disabled. + * + * A control is rendered via its {@link render()} method (the method is invoked + * by the framework.) Descendant control classes may override this method for + * customized rendering. By default, {@link render()} invokes {@link renderChildren()} + * which is responsible for rendering of children of the control. + * Control's {@link getVisible Visible} property governs whether the control + * should be rendered or not. + * + * Each control on a page will undergo a series of lifecycles, including + * control construction, Init, Load, PreRender, Render, and OnUnload. + * They work together with page lifecycles to process a page request. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TControl extends TApplicationComponent implements IRenderable, IBindable +{ + /** + * format of control ID + */ + const ID_FORMAT='/^[a-zA-Z_]\\w*$/'; + /** + * separator char between IDs in a UniqueID + */ + const ID_SEPARATOR='$'; + /** + * separator char between IDs in a ClientID + */ + const CLIENT_ID_SEPARATOR='_'; + /** + * prefix to an ID automatically generated + */ + const AUTOMATIC_ID_PREFIX='ctl'; + + /** + * the stage of lifecycles that the control is currently at + */ + const CS_CONSTRUCTED=0; + const CS_CHILD_INITIALIZED=1; + const CS_INITIALIZED=2; + const CS_STATE_LOADED=3; + const CS_LOADED=4; + const CS_PRERENDERED=5; + + /** + * State bits. + */ + const IS_ID_SET=0x01; + const IS_DISABLE_VIEWSTATE=0x02; + const IS_SKIN_APPLIED=0x04; + const IS_STYLESHEET_APPLIED=0x08; + const IS_DISABLE_THEMING=0x10; + const IS_CHILD_CREATED=0x20; + const IS_CREATING_CHILD=0x40; + + /** + * Indexes for the rare fields. + * In order to save memory, rare fields will only be created if they are needed. + */ + const RF_CONTROLS=0; // child controls + const RF_CHILD_STATE=1; // child state field + const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control + const RF_NAMED_CONTROLS_ID=3; // counter for automatic id + const RF_SKIN_ID=4; // skin ID + const RF_DATA_BINDINGS=5; // data bindings + const RF_EVENTS=6; // event handlers + const RF_CONTROLSTATE=7; // controlstate + const RF_NAMED_OBJECTS=8; // controls declared with ID on template + const RF_ADAPTER=9; // adapter + const RF_AUTO_BINDINGS=10; // auto data bindings + + /** + * @var string control ID + */ + private $_id=''; + /** + * @var string control unique ID + */ + private $_uid; + /** + * @var TControl parent of the control + */ + private $_parent; + /** + * @var TPage page that the control resides in + */ + private $_page; + /** + * @var TControl naming container of the control + */ + private $_namingContainer; + /** + * @var TTemplateControl control whose template contains the control + */ + private $_tplControl; + /** + * @var array viewstate data + */ + private $_viewState=array(); + /** + * @var array temporary state (usually set in template) + */ + private $_tempState=array(); + /** + * @var boolean whether we should keep state in viewstate + */ + private $_trackViewState=true; + /** + * @var integer the current stage of the control lifecycles + */ + private $_stage=0; + /** + * @var integer representation of the state bits + */ + private $_flags=0; + /** + * @var array a collection of rare control data + */ + private $_rf=array(); + + /** + * Constructor. + */ + public function __construct() + { + } + + /** + * Returns a property value by name or a control by ID. + * This overrides the parent implementation by allowing accessing + * a control via its ID using the following syntax, + * <code> + * $menuBar=$this->menuBar; + * </code> + * Note, the control must be configured in the template + * with explicit ID. If the name matches both a property and a control ID, + * the control ID will take the precedence. + * + * @param string the property name or control ID + * @return mixed the property value or the target control + * @throws TInvalidOperationException if the property is not defined. + * @see registerObject + */ + public function __get($name) + { + if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) + return $this->_rf[self::RF_NAMED_OBJECTS][$name]; + else + return parent::__get($name); + } + + /** + * @return boolean whether there is an adapter for this control + */ + public function getHasAdapter() + { + return isset($this->_rf[self::RF_ADAPTER]); + } + + /** + * @return TControlAdapter control adapter. Null if not exists. + */ + public function getAdapter() + { + return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null; + } + + /** + * @param TControlAdapter control adapter + */ + public function setAdapter(TControlAdapter $adapter) + { + $this->_rf[self::RF_ADAPTER]=$adapter; + } + + /** + * @return TControl the parent of this control + */ + public function getParent() + { + return $this->_parent; + } + + /** + * @return TControl the naming container of this control + */ + public function getNamingContainer() + { + if(!$this->_namingContainer && $this->_parent) + { + if($this->_parent instanceof INamingContainer) + $this->_namingContainer=$this->_parent; + else + $this->_namingContainer=$this->_parent->getNamingContainer(); + } + return $this->_namingContainer; + } + + /** + * @return TPage the page that contains this control + */ + public function getPage() + { + if(!$this->_page) + { + if($this->_parent) + $this->_page=$this->_parent->getPage(); + else if($this->_tplControl) + $this->_page=$this->_tplControl->getPage(); + } + return $this->_page; + } + + /** + * Sets the page for a control. + * Only framework developers should use this method. + * @param TPage the page that contains this control + */ + public function setPage($page) + { + $this->_page=$page; + } + + /** + * Sets the control whose template contains this control. + * Only framework developers should use this method. + * @param TTemplateControl the control whose template contains this control + */ + public function setTemplateControl($control) + { + $this->_tplControl=$control; + } + + /** + * @return TTemplateControl the control whose template contains this control + */ + public function getTemplateControl() + { + if(!$this->_tplControl && $this->_parent) + $this->_tplControl=$this->_parent->getTemplateControl(); + return $this->_tplControl; + } + + /** + * @return TTemplateControl the control whose template is loaded from + * some external storage, such as file, db, and whose template ultimately + * contains this control. + */ + public function getSourceTemplateControl() + { + $control=$this; + while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null) + { + if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl()) + return $control; + } + return $this->getPage(); + } + + /** + * Gets the lifecycle step the control is currently at. + * This method should only be used by control developers. + * @return integer the lifecycle step the control is currently at. + * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED, + * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED. + */ + protected function getControlStage() + { + return $this->_stage; + } + + /** + * Sets the lifecycle step the control is currently at. + * This method should only be used by control developers. + * @param integer the lifecycle step the control is currently at. + * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED, + * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED. + */ + protected function setControlStage($value) + { + $this->_stage=$value; + } + + /** + * Returns the id of the control. + * Control ID can be either manually set or automatically generated. + * If $hideAutoID is true, automatically generated ID will be returned as an empty string. + * @param boolean whether to hide automatically generated ID + * @return string the ID of the control + */ + public function getID($hideAutoID=true) + { + if($hideAutoID) + return ($this->_flags & self::IS_ID_SET) ? $this->_id : ''; + else + return $this->_id; + } + + /** + * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only + * @throws TInvalidDataValueException if ID is in a bad format + */ + public function setID($id) + { + if(!preg_match(self::ID_FORMAT,$id)) + throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id); + $this->_id=$id; + $this->_flags |= self::IS_ID_SET; + $this->clearCachedUniqueID($this instanceof INamingContainer); + if($this->_namingContainer) + $this->_namingContainer->clearNameTable(); + } + + /** + * Returns a unique ID that identifies the control in the page hierarchy. + * A unique ID is the contenation of all naming container controls' IDs and the control ID. + * These IDs are separated by '$' character. + * Control users should not rely on the specific format of UniqueID, however. + * @return string a unique ID that identifies the control in the page hierarchy + */ + public function getUniqueID() + { + if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID + { + $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action + if($namingContainer=$this->getNamingContainer()) + { + if($this->getPage()===$namingContainer) + return ($this->_uid=$this->_id); + else if(($prefix=$namingContainer->getUniqueID())==='') + return $this->_id; + else + return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id); + } + else // no naming container + return $this->_id; + } + else + return $this->_uid; + } + + /** + * Sets input focus to this control. + */ + public function focus() + { + $this->getPage()->setFocus($this); + } + + /** + * Returns the client ID of the control. + * The client ID can be used to uniquely identify + * the control in client-side scripts (such as JavaScript). + * Do not rely on the explicit format of the return ID. + * @return string the client ID of the control + */ + public function getClientID() + { + return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); + } + + /** + * Converts a unique ID to a client ID. + * @param string the unique ID of a control + * @return string the client ID of the control + */ + public static function convertUniqueIdToClientId($uniqueID) + { + return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); + } + + /** + * @return string the skin ID of this control, '' if not set + */ + public function getSkinID() + { + return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:''; + } + + /** + * @param string the skin ID of this control + * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already. + */ + public function setSkinID($value) + { + if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED) + throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this)); + else + $this->_rf[self::RF_SKIN_ID]=$value; + } + + /** + * @param string the skin ID of this control + * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already. + */ + public function getIsSkinApplied() + { + return ($this->_flags & self::IS_SKIN_APPLIED); + } + + /** + * @return boolean whether theming is enabled for this control. + * The theming is enabled if the control and all its parents have it enabled. + */ + public function getEnableTheming() + { + if($this->_flags & self::IS_DISABLE_THEMING) + return false; + else + return $this->_parent?$this->_parent->getEnableTheming():true; + } + + /** + * @param boolean whether to enable theming + * @throws TInvalidOperationException if this method is invoked after OnPreInit + */ + public function setEnableTheming($value) + { + if($this->_stage>=self::CS_CHILD_INITIALIZED) + throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID()); + else if(TPropertyValue::ensureBoolean($value)) + $this->_flags &= ~self::IS_DISABLE_THEMING; + else + $this->_flags |= self::IS_DISABLE_THEMING; + } + + /** + * Returns custom data associated with this control. + * A control may be associated with some custom data for various purposes. + * For example, a button may be associated with a string to identify itself + * in a generic OnClick event handler. + * @return mixed custom data associated with this control. Defaults to null. + */ + public function getCustomData() + { + return $this->getViewState('CustomData',null); + } + + /** + * Associates custom data with this control. + * Note, the custom data must be serializable and unserializable. + * @param mixed custom data + */ + public function setCustomData($value) + { + $this->setViewState('CustomData',$value,null); + } + + /** + * @return boolean whether the control has child controls + */ + public function getHasControls() + { + return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0; + } + + /** + * @return TControlCollection the child control collection + */ + public function getControls() + { + if(!isset($this->_rf[self::RF_CONTROLS])) + $this->_rf[self::RF_CONTROLS]=$this->createControlCollection(); + return $this->_rf[self::RF_CONTROLS]; + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TControlCollection control collection + * @see getControls + */ + protected function createControlCollection() + { + return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this); + } + + /** + * Checks if a control is visible. + * If parent check is required, then a control is visible only if the control + * and all its ancestors are visible. + * @param boolean whether the parents should also be checked if visible + * @return boolean whether the control is visible (default=true). + */ + public function getVisible($checkParents=true) + { + if($checkParents) + { + for($control=$this;$control;$control=$control->_parent) + if(!$control->getVisible(false)) + return false; + return true; + } + else + return $this->getViewState('Visible',true); + } + + /** + * @param boolean whether the control is visible + */ + public function setVisible($value) + { + $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Returns a value indicating whether the control is enabled. + * A control is enabled if it allows client user interaction. + * If $checkParents is true, all parent controls will be checked, + * and unless they are all enabled, false will be returned. + * The property Enabled is mainly used for {@link TWebControl} + * derived controls. + * @param boolean whether the parents should also be checked enabled + * @return boolean whether the control is enabled. + */ + public function getEnabled($checkParents=false) + { + if($checkParents) + { + for($control=$this;$control;$control=$control->_parent) + if(!$control->getViewState('Enabled',true)) + return false; + return true; + } + else + return $this->getViewState('Enabled',true); + } + + /** + * @param boolean whether the control is to be enabled. + */ + public function setEnabled($value) + { + $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the control has custom attributes + */ + public function getHasAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->getCount()>0; + else + return false; + } + + /** + * Returns the list of custom attributes. + * Custom attributes are name-value pairs that may be rendered + * as HTML tags' attributes. + * @return TAttributeCollection the list of custom attributes + */ + public function getAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes; + else + { + $attributes=new TAttributeCollection; + $this->setViewState('Attributes',$attributes,null); + return $attributes; + } + } + + /** + * @return boolean whether the named attribute exists + */ + public function hasAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->contains($name); + else + return false; + } + + /** + * @return string attribute value, null if attribute does not exist + */ + public function getAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->itemAt($name); + else + return null; + } + + /** + * Sets a custom control attribute. + * @param string attribute name + * @param string value of the attribute + */ + public function setAttribute($name,$value) + { + $this->getAttributes()->add($name,$value); + } + + /** + * Removes the named attribute. + * @param string the name of the attribute to be removed. + * @return string attribute value removed, null if attribute does not exist. + */ + public function removeAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->remove($name); + else + return null; + } + + /** + * @return boolean whether viewstate is enabled + */ + public function getEnableViewState($checkParents=false) + { + if($checkParents) + { + for($control=$this;$control!==null;$control=$control->getParent()) + if($control->_flags & self::IS_DISABLE_VIEWSTATE) + return false; + return true; + } + else + return !($this->_flags & self::IS_DISABLE_VIEWSTATE); + } + + /** + * @param boolean set whether to enable viewstate + */ + public function setEnableViewState($value) + { + if(TPropertyValue::ensureBoolean($value)) + $this->_flags &= ~self::IS_DISABLE_VIEWSTATE; + else + $this->_flags |= self::IS_DISABLE_VIEWSTATE; + } + + /** + * Returns a controlstate value. + * + * This function is mainly used in defining getter functions for control properties + * that must be kept in controlstate. + * @param string the name of the controlstate value to be returned + * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned + * @return mixed the controlstate value corresponding to $key + */ + protected function getControlState($key,$defaultValue=null) + { + return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue; + } + + /** + * Sets a controlstate value. + * + * This function is very useful in defining setter functions for control properties + * that must be kept in controlstate. + * Make sure that the controlstate value must be serializable and unserializable. + * @param string the name of the controlstate value + * @param mixed the controlstate value to be set + * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate + */ + protected function setControlState($key,$value,$defaultValue=null) + { + if($value===$defaultValue) + unset($this->_rf[self::RF_CONTROLSTATE][$key]); + else + $this->_rf[self::RF_CONTROLSTATE][$key]=$value; + } + + /** + * Clears a controlstate value. + * @param string the name of the controlstate value to be cleared + */ + protected function clearControlState($key) + { + unset($this->_rf[self::RF_CONTROLSTATE][$key]); + } + + /** + * Sets a value indicating whether we should keep data in viewstate. + * When it is false, data saved via setViewState() will not be persisted. + * By default, it is true, meaning data will be persisted across postbacks. + * @param boolean whether data should be persisted + */ + public function trackViewState($enabled) + { + $this->_trackViewState=TPropertyValue::ensureBoolean($enabled); + } + + /** + * Returns a viewstate value. + * + * This function is very useful in defining getter functions for component properties + * that must be kept in viewstate. + * @param string the name of the viewstate value to be returned + * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned + * @return mixed the viewstate value corresponding to $key + */ + public function getViewState($key,$defaultValue=null) + { + if(isset($this->_viewState[$key])) + return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue; + else if(isset($this->_tempState[$key])) + { + if(is_object($this->_tempState[$key]) && $this->_trackViewState) + $this->_viewState[$key]=$this->_tempState[$key]; + return $this->_tempState[$key]; + } + else + return $defaultValue; + } + + /** + * Sets a viewstate value. + * + * This function is very useful in defining setter functions for control properties + * that must be kept in viewstate. + * Make sure that the viewstate value must be serializable and unserializable. + * @param string the name of the viewstate value + * @param mixed the viewstate value to be set + * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate. + */ + public function setViewState($key,$value,$defaultValue=null) + { + if($this->_trackViewState) + { + $this->_viewState[$key]=$value; + unset($this->_tempState[$key]); + } + else + { + unset($this->_viewState[$key]); + $this->_tempState[$key]=$value; + } + } + + /** + * Clears a viewstate value. + * @param string the name of the viewstate value to be cleared + */ + public function clearViewState($key) + { + unset($this->_viewState[$key]); + unset($this->_tempState[$key]); + } + + /** + * Sets up the binding between a property (or property path) and an expression. + * The context of the expression is the template control (or the control itself if it is a page). + * @param string the property name, or property path + * @param string the expression + */ + public function bindProperty($name,$expression) + { + $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression; + } + + /** + * Breaks the binding between a property (or property path) and an expression. + * @param string the property name (or property path) + */ + public function unbindProperty($name) + { + unset($this->_rf[self::RF_DATA_BINDINGS][$name]); + } + + /** + * Sets up the binding between a property (or property path) and an expression. + * Unlike regular databinding, the expression bound by this method + * is automatically evaluated during {@link prerenderRecursive()}. + * The context of the expression is the template control (or the control itself if it is a page). + * @param string the property name, or property path + * @param string the expression + */ + public function autoBindProperty($name,$expression) + { + $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression; + } + + /** + * Performs the databinding for this control. + */ + public function dataBind() + { + $this->dataBindProperties(); + $this->onDataBinding(null); + $this->dataBindChildren(); + } + + /** + * Databinding properties of the control. + */ + protected function dataBindProperties() + { + Prado::trace("Data bind properties",'System.Web.UI.TControl'); + if(isset($this->_rf[self::RF_DATA_BINDINGS])) + { + if(($context=$this->getTemplateControl())===null) + $context=$this; + foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression) + $this->setSubProperty($property,$context->evaluateExpression($expression)); + } + } + + /** + * Auto databinding properties of the control. + */ + protected function autoDataBindProperties() + { + if(isset($this->_rf[self::RF_AUTO_BINDINGS])) + { + if(($context=$this->getTemplateControl())===null) + $context=$this; + foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression) + $this->setSubProperty($property,$context->evaluateExpression($expression)); + } + } + + /** + * Databinding child controls. + */ + protected function dataBindChildren() + { + Prado::trace("dataBindChildren()",'System.Web.UI.TControl'); + if(isset($this->_rf[self::RF_CONTROLS])) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof IBindable) + $control->dataBind(); + } + } + + /** + * @return boolean whether child controls have been created + */ + final protected function getChildControlsCreated() + { + return ($this->_flags & self::IS_CHILD_CREATED)!==0; + } + + /** + * Sets a value indicating whether child controls are created. + * If false, any existing child controls will be cleared up. + * @param boolean whether child controls are created + */ + final protected function setChildControlsCreated($value) + { + if($value) + $this->_flags |= self::IS_CHILD_CREATED; + else + { + if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED)) + $this->getControls()->clear(); + $this->_flags &= ~self::IS_CHILD_CREATED; + } + } + + /** + * Ensures child controls are created. + * If child controls are not created yet, this method will invoke + * {@link createChildControls} to create them. + */ + public function ensureChildControls() + { + if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD)) + { + try + { + $this->_flags |= self::IS_CREATING_CHILD; + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->createChildControls(); + else + $this->createChildControls(); + $this->_flags &= ~self::IS_CREATING_CHILD; + $this->_flags |= self::IS_CHILD_CREATED; + } + catch(Exception $e) + { + $this->_flags &= ~self::IS_CREATING_CHILD; + $this->_flags |= self::IS_CHILD_CREATED; + throw $e; + } + } + } + + /** + * Creates child controls. + * This method can be overriden for controls who want to have their controls. + * Do not call this method directly. Instead, call {@link ensureChildControls} + * to ensure child controls are created only once. + */ + public function createChildControls() + { + } + + /** + * Finds a control by ID path within the current naming container. + * The current naming container is either the control itself + * if it implements {@link INamingContainer} or the control's naming container. + * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}. + * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1' + * whose naming container is 'Item1' whose naming container is 'Repeater1'. + * @param string ID of the control to be looked up + * @return TControl|null the control found, null if not found + * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container. + */ + public function findControl($id) + { + $id=strtr($id,'.',self::ID_SEPARATOR); + $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer(); + if(!$container || !$container->getHasControls()) + return null; + if(!isset($container->_rf[self::RF_NAMED_CONTROLS])) + { + $container->_rf[self::RF_NAMED_CONTROLS]=array(); + $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]); + } + if(($pos=strpos($id,self::ID_SEPARATOR))===false) + return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null; + else + { + $cid=substr($id,0,$pos); + $sid=substr($id,$pos+1); + if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid])) + return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid); + else + return null; + } + } + + /** + * Finds all child and grand-child controls that are of the specified type. + * @param string the class name + * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned. + * @return array list of controls found + */ + public function findControlsByType($type,$strict=true) + { + $controls=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type)))) + $controls[]=$control; + if(($control instanceof TControl) && $control->getHasControls()) + $controls=array_merge($controls,$control->findControlsByType($type,$strict)); + } + } + return $controls; + } + + /** + * Finds all child and grand-child controls with the specified ID. + * Note, this method is different from {@link findControl} in that + * it searches through all controls that have this control as the ancestor + * while {@link findcontrol} only searches through controls that have this + * control as the direct naming container. + * @param string the ID being looked for + * @return array list of controls found + */ + public function findControlsByID($id) + { + $controls=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + if($control->_id===$id) + $controls[]=$control; + $controls=array_merge($controls,$control->findControlsByID($id)); + } + } + } + return $controls; + } + + /** + * Resets the control as a naming container. + * Only framework developers should use this method. + */ + public function clearNamingContainer() + { + unset($this->_rf[self::RF_NAMED_CONTROLS_ID]); + $this->clearNameTable(); + } + + /** + * Registers an object by a name. + * A registered object can be accessed like a public member variable. + * This method should only be used by framework and control developers. + * @param string name of the object + * @param object object to be declared + * @see __get + */ + public function registerObject($name,$object) + { + if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) + throw new TInvalidOperationException('control_object_reregistered',$name); + $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object; + } + + /** + * Unregisters an object by name. + * @param string name of the object + * @see registerObject + */ + public function unregisterObject($name) + { + unset($this->_rf[self::RF_NAMED_OBJECTS][$name]); + } + + /** + * @return boolean whether an object has been registered with the name + * @see registerObject + */ + public function isObjectRegistered($name) + { + return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]); + } + + /** + * @return boolean true if the child control has been initialized. + */ + public function getHasChildInitialized() + { + return $this->getControlStage() >= self::CS_CHILD_INITIALIZED; + } + + /** + * @return boolean true if the onInit event has raised. + */ + public function getHasInitialized() + { + return $this->getControlStage() >= self::CS_INITIALIZED; + } + + /** + * @return boolean true if the control has loaded post data. + */ + public function getHasLoadedPostData() + { + return $this->getControlStage() >= self::CS_STATE_LOADED; + } + + /** + * @return boolean true if the onLoad event has raised. + */ + public function getHasLoaded() + { + return $this->getControlStage() >= self::CS_LOADED; + } + + /** + * @return boolean true if onPreRender event has raised. + */ + public function getHasPreRendered() + { + return $this->getControlStage() >= self::CS_PRERENDERED; + } + + /** + * Returns the named registered object. + * A component with explicit ID on a template will be registered to + * the template owner. This method allows you to obtain this component + * with the ID. + * @return mixed the named registered object. Null if object is not found. + */ + public function getRegisteredObject($name) + { + return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null; + } + + /** + * @return boolean whether body contents are allowed for this control. Defaults to true. + */ + public function getAllowChildControls() + { + return true; + } + + /** + * Adds the object instantiated on a template to the child control collection. + * This method overrides the parent implementation. + * Only framework developers and control developers should use this method. + * @param string|TComponent text string or component parsed and instantiated in template + * @see createdOnTemplate + */ + public function addParsedObject($object) + { + $this->getControls()->add($object); + } + + /** + * Clears up the child state data. + * After a control loads its state, those state that do not belong to + * any existing child controls are stored as child state. + * This method will remove these state. + * Only frameworker developers and control developers should use this method. + */ + final protected function clearChildState() + { + unset($this->_rf[self::RF_CHILD_STATE]); + } + + /** + * @param TControl the potential ancestor control + * @return boolean if the control is a descendent (parent, parent of parent, etc.) + * of the specified control + */ + final protected function isDescendentOf($ancestor) + { + $control=$this; + while($control!==$ancestor && $control->_parent) + $control=$control->_parent; + return $control===$ancestor; + } + + /** + * Adds a control into the child collection of the control. + * Control lifecycles will be caught up during the addition. + * Only framework developers should use this method. + * @param TControl the new child control + */ + public function addedControl($control) + { + if($control->_parent) + $control->_parent->getControls()->remove($control); + $control->_parent=$this; + $control->_page=$this->getPage(); + $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer; + if($namingContainer) + { + $control->_namingContainer=$namingContainer; + if($control->_id==='') + $control->generateAutomaticID(); + else + $namingContainer->clearNameTable(); + $control->clearCachedUniqueID($control instanceof INamingContainer); + } + + if($this->_stage>=self::CS_CHILD_INITIALIZED) + { + $control->initRecursive($namingContainer); + if($this->_stage>=self::CS_STATE_LOADED) + { + if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id])) + { + $state=$this->_rf[self::RF_CHILD_STATE][$control->_id]; + unset($this->_rf[self::RF_CHILD_STATE][$control->_id]); + } + else + $state=null; + $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE)); + if($this->_stage>=self::CS_LOADED) + { + $control->loadRecursive(); + if($this->_stage>=self::CS_PRERENDERED) + $control->preRenderRecursive(); + } + } + } + } + + /** + * Removes a control from the child collection of the control. + * Only framework developers should use this method. + * @param TControl the child control removed + */ + public function removedControl($control) + { + if($this->_namingContainer) + $this->_namingContainer->clearNameTable(); + $control->unloadRecursive(); + $control->_parent=null; + $control->_page=null; + $control->_namingContainer=null; + $control->_tplControl=null; + //$control->_stage=self::CS_CONSTRUCTED; + if(!($control->_flags & self::IS_ID_SET)) + $control->_id=''; + else + unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]); + $control->clearCachedUniqueID(true); + } + + /** + * Performs the Init step for the control and all its child controls. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + if($this->getHasControls()) + { + if($this instanceof INamingContainer) + $namingContainer=$this; + $page=$this->getPage(); + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + $control->_namingContainer=$namingContainer; + $control->_page=$page; + if($control->_id==='' && $namingContainer) + $control->generateAutomaticID(); + $control->initRecursive($namingContainer); + } + } + } + if($this->_stage<self::CS_INITIALIZED) + { + $this->_stage=self::CS_CHILD_INITIALIZED; + if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED)) + { + $page->applyControlSkin($this); + $this->_flags |= self::IS_SKIN_APPLIED; + } + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onInit(null); + else + $this->onInit(null); + $this->_stage=self::CS_INITIALIZED; + } + } + + /** + * Performs the Load step for the control and all its child controls. + * Only framework developers should use this method. + */ + protected function loadRecursive() + { + if($this->_stage<self::CS_LOADED) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onLoad(null); + else + $this->onLoad(null); + } + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->loadRecursive(); + } + } + if($this->_stage<self::CS_LOADED) + $this->_stage=self::CS_LOADED; + } + + /** + * Performs the PreRender step for the control and all its child controls. + * Only framework developers should use this method. + */ + protected function preRenderRecursive() + { + $this->autoDataBindProperties(); + + if($this->getVisible(false)) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onPreRender(null); + else + $this->onPreRender(null); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->preRenderRecursive(); + else if($control instanceof TCompositeLiteral) + $control->evaluateDynamicContent(); + } + } + $this->addToPostDataLoader(); + } + $this->_stage=self::CS_PRERENDERED; + } + + /** + * Add controls implementing IPostBackDataHandler to post data loaders. + */ + protected function addToPostDataLoader() + { + if($this instanceof IPostBackDataHandler) + $this->getPage()->registerPostDataLoader($this); + } + + /** + * Performs the Unload step for the control and all its child controls. + * Only framework developers should use this method. + */ + protected function unloadRecursive() + { + if(!($this->_flags & self::IS_ID_SET)) + $this->_id=''; + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof TControl) + $control->unloadRecursive(); + } + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onUnload(null); + else + $this->onUnload(null); + } + + /** + * This method is invoked when the control enters 'OnInit' stage. + * The method raises 'OnInit' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onInit($param) + { + $this->raiseEvent('OnInit',$this,$param); + } + + /** + * This method is invoked when the control enters 'OnLoad' stage. + * The method raises 'OnLoad' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onLoad($param) + { + $this->raiseEvent('OnLoad',$this,$param); + } + + /** + * Raises 'OnDataBinding' event. + * This method is invoked when {@link dataBind} is invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onDataBinding($param) + { + Prado::trace("onDataBinding()",'System.Web.UI.TControl'); + $this->raiseEvent('OnDataBinding',$this,$param); + } + + + /** + * This method is invoked when the control enters 'OnUnload' stage. + * The method raises 'OnUnload' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onUnload($param) + { + $this->raiseEvent('OnUnload',$this,$param); + } + + /** + * This method is invoked when the control enters 'OnPreRender' stage. + * The method raises 'OnPreRender' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onPreRender($param) + { + $this->raiseEvent('OnPreRender',$this,$param); + } + + /** + * Invokes the parent's bubbleEvent method. + * A control who wants to bubble an event must call this method in its onEvent method. + * @param TControl sender of the event + * @param TEventParameter event parameter + * @see bubbleEvent + */ + protected function raiseBubbleEvent($sender,$param) + { + $control=$this; + while($control=$control->_parent) + { + if($control->bubbleEvent($sender,$param)) + break; + } + } + + /** + * This method responds to a bubbled event. + * This method should be overriden to provide customized response to a bubbled event. + * Check the type of event parameter to determine what event is bubbled currently. + * @param TControl sender of the event + * @param TEventParameter event parameters + * @return boolean true if the event bubbling is handled and no more bubbling. + * @see raiseBubbleEvent + */ + public function bubbleEvent($sender,$param) + { + return false; + } + + /** + * Broadcasts an event. + * The event will be sent to all controls on the current page hierarchy. + * If a control defines the event, the event will be raised for the control. + * If a control implements {@link IBroadcastEventReceiver}, its + * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will + * be invoked which gives the control a chance to respond to the event. + * For example, when broadcasting event 'OnClick', all controls having 'OnClick' + * event will have this event raised, and all controls implementing + * {@link IBroadcastEventReceiver} will also have its + * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} + * invoked. + * @param string name of the broadcast event + * @param TControl sender of this event + * @param TEventParameter event parameter + */ + public function broadcastEvent($name,$sender,$param) + { + $rootControl=(($page=$this->getPage())===null)?$this:$page; + $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param)); + } + + /** + * Recursively broadcasts an event. + * This method should only be used by framework developers. + * @param string name of the broadcast event + * @param TControl sender of the event + * @param TBroadcastEventParameter event parameter + */ + private function broadcastEventInternal($name,$sender,$param) + { + if($this->hasEvent($name)) + $this->raiseEvent($name,$sender,$param->getParameter()); + if($this instanceof IBroadcastEventReceiver) + $this->broadcastEventReceived($sender,$param); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->broadcastEventInternal($name,$sender,$param); + } + } + } + + /** + * Traverse the whole control hierarchy rooted at this control. + * Callback function may be invoked for each control being visited. + * A pre-callback is invoked before traversing child controls; + * A post-callback is invoked after traversing child controls. + * Callback functions can be global functions or class methods. + * They must be of the following signature: + * <code> + * function callback_func($control,$param) {...} + * </code> + * where $control refers to the control being visited and $param + * is the parameter that is passed originally when calling this traverse function. + * + * @param mixed parameter to be passed to callbacks for each control + * @param callback callback invoked before traversing child controls. If null, it is ignored. + * @param callback callback invoked after traversing child controls. If null, it is ignored. + */ + protected function traverseChildControls($param,$preCallback=null,$postCallback=null) + { + if($preCallback!==null) + call_user_func($preCallback,$this,$param); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + $control->traverseChildControls($param,$preCallback,$postCallback); + } + } + } + if($postCallback!==null) + call_user_func($postCallback,$this,$param); + } + + /** + * Renders the control. + * Only when the control is visible will the control be rendered. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderControl($writer) + { + if($this instanceof IActiveControl || $this->getVisible(false)) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->render($writer); + else + $this->render($writer); + } + } + + /** + * Renders the control. + * This method is invoked by {@link renderControl} when the control is visible. + * You can override this method to provide customized rendering of the control. + * By default, the control simply renders all its child contents. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + $this->renderChildren($writer); + } + + /** + * Renders the children of the control. + * This method iterates through all child controls and static text strings + * and renders them in order. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderChildren($writer) + { + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if(is_string($control)) + $writer->write($control); + else if($control instanceof TControl) + $control->renderControl($writer); + else if($control instanceof IRenderable) + $control->render($writer); + } + } + } + + /** + * 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() + { + } + + /** + * 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() + { + } + + /** + * Loads state (viewstate and controlstate) into a control and its children. + * This method should only be used by framework developers. + * @param array the collection of the state + * @param boolean whether the viewstate should be loaded + */ + protected function loadStateRecursive(&$state,$needViewState=true) + { + if(is_array($state)) + { + // A null state means the stateful properties all take default values. + // So if the state is enabled, we have to assign the null value. + $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); + if(isset($state[1])) + { + $this->_rf[self::RF_CONTROLSTATE]=&$state[1]; + unset($state[1]); + } + else + unset($this->_rf[self::RF_CONTROLSTATE]); + if($needViewState) + { + if(isset($state[0])) + $this->_viewState=&$state[0]; + else + $this->_viewState=array(); + } + unset($state[0]); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + if(isset($state[$control->_id])) + { + $control->loadStateRecursive($state[$control->_id],$needViewState); + unset($state[$control->_id]); + } + } + } + } + if(!empty($state)) + $this->_rf[self::RF_CHILD_STATE]=&$state; + } + $this->_stage=self::CS_STATE_LOADED; + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->loadState(); + else + $this->loadState(); + } + + /** + * Saves all control state (viewstate and controlstate) as a collection. + * This method should only be used by framework developers. + * @param boolean whether the viewstate should be saved + * @return array the collection of the control state (including its children's state). + */ + protected function &saveStateRecursive($needViewState=true) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->saveState(); + else + $this->saveState(); + $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); + $state=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $state[$control->_id]=&$control->saveStateRecursive($needViewState); + } + } + if($needViewState && !empty($this->_viewState)) + $state[0]=&$this->_viewState; + if(isset($this->_rf[self::RF_CONTROLSTATE])) + $state[1]=&$this->_rf[self::RF_CONTROLSTATE]; + return $state; + } + + /** + * Applies a stylesheet skin to a control. + * @param TPage the page containing the control + * @throws TInvalidOperationException if the stylesheet skin is applied already + */ + public function applyStyleSheetSkin($page) + { + if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED)) + { + $page->applyControlStyleSheet($this); + $this->_flags |= self::IS_STYLESHEET_APPLIED; + } + else if($this->_flags & self::IS_STYLESHEET_APPLIED) + throw new TInvalidOperationException('control_stylesheet_applied',get_class($this)); + } + + /** + * Clears the cached UniqueID. + * If $recursive=true, all children's cached UniqueID will be cleared as well. + * @param boolean whether the clearing is recursive. + */ + private function clearCachedUniqueID($recursive) + { + if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS])) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof TControl) + $control->clearCachedUniqueID($recursive); + } + $this->_uid=null; + } + + /** + * Generates an automatic ID for the control. + */ + private function generateAutomaticID() + { + $this->_flags &= ~self::IS_ID_SET; + if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID])) + $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0; + $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++; + $this->_id=self::AUTOMATIC_ID_PREFIX . $id; + $this->_namingContainer->clearNameTable(); + } + + /** + * Clears the list of the controls whose IDs are managed by the specified naming container. + */ + private function clearNameTable() + { + unset($this->_rf[self::RF_NAMED_CONTROLS]); + } + + /** + * Updates the list of the controls whose IDs are managed by the specified naming container. + * @param TControl the naming container + * @param TControlCollection list of controls + * @throws TInvalidDataValueException if a control's ID is not unique within its naming container. + */ + private function fillNameTable($container,$controls) + { + foreach($controls as $control) + { + if($control instanceof TControl) + { + if($control->_id!=='') + { + if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id])) + throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id); + else + $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control; + } + if(!($control instanceof INamingContainer) && $control->getHasControls()) + $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]); + } + } + } +} + + +/** + * TControlCollection class + * + * TControlCollection implements a collection that enables + * controls to maintain a list of their child controls. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <b>OnClick</b> event. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param); + + /** + * Raises <b>OnCommand</b> 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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <b>Command</b> + * 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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 <qiang.xue@gmail.com> + * @version $Id$ + * @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)); + } +} + +?> diff --git a/framework/Web/UI/TControlAdapter.php b/framework/Web/UI/TControlAdapter.php index 5f06c360..a1afd353 100644 --- a/framework/Web/UI/TControlAdapter.php +++ b/framework/Web/UI/TControlAdapter.php @@ -1,143 +1,143 @@ -<?php
-/**
- * TControlAdapter class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TControlAdapter class
- *
- * TControlAdapter is the base class for adapters that customize
- * various behaviors for the control to which the adapter is attached.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControlAdapter extends TApplicationComponent
-{
- /**
- * @var TControl the control to which the adapter is attached
- */
- protected $_control;
-
- /**
- * Constructor.
- * @param TControl the control to which the adapter is attached
- */
- public function __construct($control)
- {
- $this->_control=$control;
- }
-
- /**
- * @return TControl the control to which this adapter is attached
- */
- public function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @return TPage the page that contains the attached control
- */
- public function getPage()
- {
- return $this->_control?$this->_control->getPage():null;
- }
-
- /**
- * Creates child controls for the attached control.
- * Default implementation calls the attached control's corresponding method.
- */
- public function createChildControls()
- {
- $this->_control->createChildControls();
- }
-
- /**
- * Loads additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function loadState()
- {
- $this->_control->loadState();
- }
-
- /**
- * Saves additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function saveState()
- {
- $this->_control->saveState();
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->_control->onInit($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->_control->onLoad($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->_control->onPreRender($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->_control->onUnload($param);
- }
-
- /**
- * This method is invoked when the control renders itself.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- $this->_control->render($writer);
- }
-
- /**
- * Renders the control's children.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderChildren($writer)
- {
- $this->_control->renderChildren($writer);
- }
-}
-
+<?php +/** + * TControlAdapter class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TControlAdapter class + * + * TControlAdapter is the base class for adapters that customize + * various behaviors for the control to which the adapter is attached. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TControlAdapter extends TApplicationComponent +{ + /** + * @var TControl the control to which the adapter is attached + */ + protected $_control; + + /** + * Constructor. + * @param TControl the control to which the adapter is attached + */ + public function __construct($control) + { + $this->_control=$control; + } + + /** + * @return TControl the control to which this adapter is attached + */ + public function getControl() + { + return $this->_control; + } + + /** + * @return TPage the page that contains the attached control + */ + public function getPage() + { + return $this->_control?$this->_control->getPage():null; + } + + /** + * Creates child controls for the attached control. + * Default implementation calls the attached control's corresponding method. + */ + public function createChildControls() + { + $this->_control->createChildControls(); + } + + /** + * Loads additional persistent control state. + * Default implementation calls the attached control's corresponding method. + */ + public function loadState() + { + $this->_control->loadState(); + } + + /** + * Saves additional persistent control state. + * Default implementation calls the attached control's corresponding method. + */ + public function saveState() + { + $this->_control->saveState(); + } + + /** + * This method is invoked when the control enters 'OnInit' stage. + * Default implementation calls the attached control's corresponding method. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onInit($param) + { + $this->_control->onInit($param); + } + + /** + * This method is invoked when the control enters 'OnLoad' stage. + * Default implementation calls the attached control's corresponding method. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onLoad($param) + { + $this->_control->onLoad($param); + } + + /** + * This method is invoked when the control enters 'OnPreRender' stage. + * Default implementation calls the attached control's corresponding method. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onPreRender($param) + { + $this->_control->onPreRender($param); + } + + /** + * This method is invoked when the control enters 'OnUnload' stage. + * Default implementation calls the attached control's corresponding method. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onUnload($param) + { + $this->_control->onUnload($param); + } + + /** + * This method is invoked when the control renders itself. + * Default implementation calls the attached control's corresponding method. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + $this->_control->render($writer); + } + + /** + * Renders the control's children. + * Default implementation calls the attached control's corresponding method. + * @param THtmlWriter writer for the rendering purpose + */ + public function renderChildren($writer) + { + $this->_control->renderChildren($writer); + } +} + diff --git a/framework/Web/UI/TForm.php b/framework/Web/UI/TForm.php index f57f7482..2d60a4e4 100644 --- a/framework/Web/UI/TForm.php +++ b/framework/Web/UI/TForm.php @@ -1,171 +1,171 @@ -<?php
-/**
- * TForm class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TForm class
- *
- * TForm displays an HTML form. Besides regular body content,
- * it displays hidden fields, javascript blocks and files that are registered
- * through {@link TClientScriptManager}.
- *
- * A TForm is required for a page that needs postback.
- * Each page can contain at most one TForm. If multiple HTML forms are needed,
- * please use regular HTML form tags for those forms that post to different
- * URLs.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TForm extends TControl
-{
- /**
- * Registers the form with the page.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setForm($this);
- }
-
- /**
- * Adds form specific attributes to renderer.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $writer->addAttribute('method',$this->getMethod());
- $uri=$this->getRequest()->getRequestURI();
- $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri)));
- if(($enctype=$this->getEnctype())!=='')
- $writer->addAttribute('enctype',$enctype);
-
- $attributes=$this->getAttributes();
- $attributes->remove('action');
- $writer->addAttributes($attributes);
-
- if(($butt=$this->getDefaultButton())!=='')
- {
- if(($button=$this->findControl($butt))!==null)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- else
- throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
- }
- }
-
- /**
- * Renders the form.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- $page=$this->getPage();
-
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag('form');
-
- $cs=$page->getClientScript();
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHiddenFieldsBegin($writer);
- $cs->renderScriptFilesBegin($writer);
- $cs->renderBeginScripts($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $cs->renderHiddenFieldsEnd($writer);
- $page->endFormRender($writer);
-
- $cs->renderScriptFilesEnd($writer);
- $cs->renderEndScripts($writer);
- }
- else
- {
- $cs->renderHiddenFieldsBegin($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $page->endFormRender($writer);
-
- $cs->renderHiddenFieldsEnd($writer);
- }
-
- $writer->renderEndTag();
- }
-
- /**
- * @return string id path to the default button control.
- */
- public function getDefaultButton()
- {
- return $this->getViewState('DefaultButton','');
- }
-
- /**
- * Sets a button to be default one in a form.
- * A default button will be clicked if a user presses 'Enter' key within
- * the form.
- * @param string id path to the default button control.
- */
- public function setDefaultButton($value)
- {
- $this->setViewState('DefaultButton',$value,'');
- }
-
- /**
- * @return string form submission method. Defaults to 'post'.
- */
- public function getMethod()
- {
- return $this->getViewState('Method','post');
- }
-
- /**
- * @param string form submission method. Valid values include 'post' and 'get'.
- */
- public function setMethod($value)
- {
- $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
- }
-
- /**
- * @return string the encoding type a browser uses to post data back to the server
- */
- public function getEnctype()
- {
- return $this->getViewState('Enctype','');
- }
-
- /**
- * @param string the encoding type a browser uses to post data back to the server.
- * Commonly used types include
- * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
- * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
- * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
- */
- public function setEnctype($value)
- {
- $this->setViewState('Enctype',$value,'');
- }
-
- /**
- * @return string form name, which is equal to {@link getUniqueID UniqueID}.
- */
- public function getName()
- {
- return $this->getUniqueID();
- }
-}
-
+<?php +/** + * TForm class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TForm class + * + * TForm displays an HTML form. Besides regular body content, + * it displays hidden fields, javascript blocks and files that are registered + * through {@link TClientScriptManager}. + * + * A TForm is required for a page that needs postback. + * Each page can contain at most one TForm. If multiple HTML forms are needed, + * please use regular HTML form tags for those forms that post to different + * URLs. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TForm extends TControl +{ + /** + * Registers the form with the page. + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $this->getPage()->setForm($this); + } + + /** + * Adds form specific attributes to renderer. + * @param THtmlWriter writer + */ + protected function addAttributesToRender($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $writer->addAttribute('method',$this->getMethod()); + $uri=$this->getRequest()->getRequestURI(); + $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri))); + if(($enctype=$this->getEnctype())!=='') + $writer->addAttribute('enctype',$enctype); + + $attributes=$this->getAttributes(); + $attributes->remove('action'); + $writer->addAttributes($attributes); + + if(($butt=$this->getDefaultButton())!=='') + { + if(($button=$this->findControl($butt))!==null) + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + else + throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt); + } + } + + /** + * Renders the form. + * @param THtmlWriter writer + */ + public function render($writer) + { + $page=$this->getPage(); + + $this->addAttributesToRender($writer); + $writer->renderBeginTag('form'); + + $cs=$page->getClientScript(); + if($page->getClientSupportsJavaScript()) + { + $cs->renderHiddenFieldsBegin($writer); + $cs->renderScriptFilesBegin($writer); + $cs->renderBeginScripts($writer); + + $page->beginFormRender($writer); + $this->renderChildren($writer); + $cs->renderHiddenFieldsEnd($writer); + $page->endFormRender($writer); + + $cs->renderScriptFilesEnd($writer); + $cs->renderEndScripts($writer); + } + else + { + $cs->renderHiddenFieldsBegin($writer); + + $page->beginFormRender($writer); + $this->renderChildren($writer); + $page->endFormRender($writer); + + $cs->renderHiddenFieldsEnd($writer); + } + + $writer->renderEndTag(); + } + + /** + * @return string id path to the default button control. + */ + public function getDefaultButton() + { + return $this->getViewState('DefaultButton',''); + } + + /** + * Sets a button to be default one in a form. + * A default button will be clicked if a user presses 'Enter' key within + * the form. + * @param string id path to the default button control. + */ + public function setDefaultButton($value) + { + $this->setViewState('DefaultButton',$value,''); + } + + /** + * @return string form submission method. Defaults to 'post'. + */ + public function getMethod() + { + return $this->getViewState('Method','post'); + } + + /** + * @param string form submission method. Valid values include 'post' and 'get'. + */ + public function setMethod($value) + { + $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post'); + } + + /** + * @return string the encoding type a browser uses to post data back to the server + */ + public function getEnctype() + { + return $this->getViewState('Enctype',''); + } + + /** + * @param string the encoding type a browser uses to post data back to the server. + * Commonly used types include + * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format. + * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page. + * - text/plain : Form data is encoded in plain text, without any control or formatting characters. + */ + public function setEnctype($value) + { + $this->setViewState('Enctype',$value,''); + } + + /** + * @return string form name, which is equal to {@link getUniqueID UniqueID}. + */ + public function getName() + { + return $this->getUniqueID(); + } +} + diff --git a/framework/Web/UI/THtmlWriter.php b/framework/Web/UI/THtmlWriter.php index 96e1a5e1..9e264c77 100644 --- a/framework/Web/UI/THtmlWriter.php +++ b/framework/Web/UI/THtmlWriter.php @@ -1,229 +1,229 @@ -<?php
-/**
- * THtmlWriter class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THtmlWriter class
- *
- * THtmlWriter is a writer that renders valid XHTML outputs.
- * It provides functions to render tags, their attributes and stylesheet fields.
- * Attribute and stylesheet values will be automatically HTML-encoded if
- * they require so. For example, the 'value' attribute in an input tag
- * will be encoded.
- *
- * A common usage of THtmlWriter is as the following sequence:
- * <code>
- * $writer->addAttribute($name1,$value1);
- * $writer->addAttribute($name2,$value2);
- * $writer->renderBeginTag($tagName);
- * // ... render contents enclosed within the tag here
- * $writer->renderEndTag();
- * </code>
- * Make sure each invocation of {@link renderBeginTag} is accompanied with
- * a {@link renderEndTag} and they are properly nested, like nesting
- * tags in HTML and XHTML.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THtmlWriter extends TApplicationComponent implements ITextWriter
-{
- /**
- * @var array list of tags are do not need a closing tag
- */
- private static $_simpleTags=array(
- 'area'=>true,
- 'base'=>true,
- 'basefont'=>true,
- 'bgsound'=>true,
- 'col'=>true,
- 'embed'=>true,
- 'frame'=>true,
- 'hr'=>true,
- 'img'=>true,
- 'input'=>true,
- 'isindex'=>true,
- 'link'=>true,
- 'meta'=>true,
- 'wbr'=>true,
- );
- /**
- * @var array list of attributes to be rendered for a tag
- */
- private $_attributes=array();
- /**
- * @var array list of openning tags
- */
- private $_openTags=array();
- /**
- * @var array list of style attributes
- */
- private $_styles=array();
- /**
- * @var ITextWriter writer
- */
- private $_writer=null;
-
- /**
- * Constructor.
- * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
- */
- public function __construct($writer)
- {
- $this->_writer=$writer;
- }
-
- public function getWriter()
- {
- return $this->_writer;
- }
-
- public function setWriter($writer)
- {
- $this->_writer = $writer;
- }
- /**
- * Adds a list of attributes to be rendered.
- * @param array list of attributes to be rendered
- */
- public function addAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds an attribute to be rendered.
- * @param string name of the attribute
- * @param string value of the attribute
- */
- public function addAttribute($name,$value)
- {
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named attribute from rendering
- * @param string name of the attribute to be removed
- */
- public function removeAttribute($name)
- {
- unset($this->_attributes[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Adds a list of stylesheet attributes to be rendered.
- * @param array list of stylesheet attributes to be rendered
- */
- public function addStyleAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds a stylesheet attribute to be rendered
- * @param string stylesheet attribute name
- * @param string stylesheet attribute value
- */
- public function addStyleAttribute($name,$value)
- {
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named stylesheet attribute from rendering
- * @param string name of the stylesheet attribute to be removed
- */
- public function removeStyleAttribute($name)
- {
- unset($this->_styles[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Flushes the rendering result.
- * This will invoke the underlying writer's flush method.
- * @return string the content being flushed
- */
- public function flush()
- {
- return $this->_writer->flush();
- }
-
- /**
- * Renders a string.
- * @param string string to be rendered
- */
- public function write($str)
- {
- $this->_writer->write($str);
- }
-
- /**
- * Renders a string and appends a newline to it.
- * @param string string to be rendered
- */
- public function writeLine($str='')
- {
- $this->_writer->write($str."\n");
- }
-
- /**
- * Renders an HTML break.
- */
- public function writeBreak()
- {
- $this->_writer->write('<br/>');
- }
-
- /**
- * Renders the openning tag.
- * @param string tag name
- */
- public function renderBeginTag($tagName)
- {
- $str='<'.$tagName;
- foreach($this->_attributes as $name=>$value)
- $str.=' '.$name.'="'.$value.'"';
- if(!empty($this->_styles))
- {
- $str.=' style="';
- foreach($this->_styles as $name=>$value)
- $str.=$name.':'.$value.';';
- $str.='"';
- }
- if(isset(self::$_simpleTags[$tagName]))
- {
- $str.=' />';
- $this->_openTags[] = '';
- }
- else
- {
- $str.='>';
- $this->_openTags[] = $tagName;
- }
- $this->_writer->write($str);
- $this->_attributes=array();
- $this->_styles=array();
- }
-
- /**
- * Renders the closing tag.
- */
- public function renderEndTag()
- {
- if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
- $this->_writer->write('</'.$tagName.'>');
- }
-}
-
+<?php +/** + * THtmlWriter class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * THtmlWriter class + * + * THtmlWriter is a writer that renders valid XHTML outputs. + * It provides functions to render tags, their attributes and stylesheet fields. + * Attribute and stylesheet values will be automatically HTML-encoded if + * they require so. For example, the 'value' attribute in an input tag + * will be encoded. + * + * A common usage of THtmlWriter is as the following sequence: + * <code> + * $writer->addAttribute($name1,$value1); + * $writer->addAttribute($name2,$value2); + * $writer->renderBeginTag($tagName); + * // ... render contents enclosed within the tag here + * $writer->renderEndTag(); + * </code> + * Make sure each invocation of {@link renderBeginTag} is accompanied with + * a {@link renderEndTag} and they are properly nested, like nesting + * tags in HTML and XHTML. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class THtmlWriter extends TApplicationComponent implements ITextWriter +{ + /** + * @var array list of tags are do not need a closing tag + */ + private static $_simpleTags=array( + 'area'=>true, + 'base'=>true, + 'basefont'=>true, + 'bgsound'=>true, + 'col'=>true, + 'embed'=>true, + 'frame'=>true, + 'hr'=>true, + 'img'=>true, + 'input'=>true, + 'isindex'=>true, + 'link'=>true, + 'meta'=>true, + 'wbr'=>true, + ); + /** + * @var array list of attributes to be rendered for a tag + */ + private $_attributes=array(); + /** + * @var array list of openning tags + */ + private $_openTags=array(); + /** + * @var array list of style attributes + */ + private $_styles=array(); + /** + * @var ITextWriter writer + */ + private $_writer=null; + + /** + * Constructor. + * @param ITextWriter a writer that THtmlWriter will pass its rendering result to + */ + public function __construct($writer) + { + $this->_writer=$writer; + } + + public function getWriter() + { + return $this->_writer; + } + + public function setWriter($writer) + { + $this->_writer = $writer; + } + /** + * Adds a list of attributes to be rendered. + * @param array list of attributes to be rendered + */ + public function addAttributes($attrs) + { + foreach($attrs as $name=>$value) + $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value); + } + + /** + * Adds an attribute to be rendered. + * @param string name of the attribute + * @param string value of the attribute + */ + public function addAttribute($name,$value) + { + $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value); + } + + /** + * Removes the named attribute from rendering + * @param string name of the attribute to be removed + */ + public function removeAttribute($name) + { + unset($this->_attributes[THttpUtility::htmlStrip($name)]); + } + + /** + * Adds a list of stylesheet attributes to be rendered. + * @param array list of stylesheet attributes to be rendered + */ + public function addStyleAttributes($attrs) + { + foreach($attrs as $name=>$value) + $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value); + } + + /** + * Adds a stylesheet attribute to be rendered + * @param string stylesheet attribute name + * @param string stylesheet attribute value + */ + public function addStyleAttribute($name,$value) + { + $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value); + } + + /** + * Removes the named stylesheet attribute from rendering + * @param string name of the stylesheet attribute to be removed + */ + public function removeStyleAttribute($name) + { + unset($this->_styles[THttpUtility::htmlStrip($name)]); + } + + /** + * Flushes the rendering result. + * This will invoke the underlying writer's flush method. + * @return string the content being flushed + */ + public function flush() + { + return $this->_writer->flush(); + } + + /** + * Renders a string. + * @param string string to be rendered + */ + public function write($str) + { + $this->_writer->write($str); + } + + /** + * Renders a string and appends a newline to it. + * @param string string to be rendered + */ + public function writeLine($str='') + { + $this->_writer->write($str."\n"); + } + + /** + * Renders an HTML break. + */ + public function writeBreak() + { + $this->_writer->write('<br/>'); + } + + /** + * Renders the openning tag. + * @param string tag name + */ + public function renderBeginTag($tagName) + { + $str='<'.$tagName; + foreach($this->_attributes as $name=>$value) + $str.=' '.$name.'="'.$value.'"'; + if(!empty($this->_styles)) + { + $str.=' style="'; + foreach($this->_styles as $name=>$value) + $str.=$name.':'.$value.';'; + $str.='"'; + } + if(isset(self::$_simpleTags[$tagName])) + { + $str.=' />'; + $this->_openTags[] = ''; + } + else + { + $str.='>'; + $this->_openTags[] = $tagName; + } + $this->_writer->write($str); + $this->_attributes=array(); + $this->_styles=array(); + } + + /** + * Renders the closing tag. + */ + public function renderEndTag() + { + if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='') + $this->_writer->write('</'.$tagName.'>'); + } +} + diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 37326031..26a06b64 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -1,1341 +1,1341 @@ -<?php
-/**
- * TPage class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @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>
- * @version $Id$
- * @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 array post data loader IDs.
- */
- protected $_postDataLoaders=array();
- /**
- * @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));
-
- // 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);
- }
-
- /**
- * Register post data loaders for Callback to collect post data.
- * This method should only be called by framework developers.
- * @param TControl control that requires post data.
- * @see TControl::preRenderRecursive();
- */
- public function registerPostDataLoader($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_postDataLoaders[$id] = true;
- }
-
- /**
- * Get a list of IDs of controls that are enabled and require post data.
- * @return array list of IDs implementing IPostBackDataHandler
- */
- public function getPostDataLoaders()
- {
- return array_keys($this->_postDataLoaders);
- }
-
- /**
- * @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;
- $this->registerPostDataLoader($id);
- $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());
- }
-}
-
-/**
- * IPageStatePersister interface.
- *
- * IPageStatePersister interface is required for all page state persister
- * classes.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @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(Prado::serialize($data));
- else
- $str=Prado::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 Prado::unserialize($str);
- }
- else
- return Prado::unserialize($str);
- }
- return null;
- }
-}
+<?php +/** + * TPage class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @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> + * @version $Id$ + * @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 array post data loader IDs. + */ + protected $_postDataLoaders=array(); + /** + * @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)); + + // 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); + } + + /** + * Register post data loaders for Callback to collect post data. + * This method should only be called by framework developers. + * @param TControl control that requires post data. + * @see TControl::preRenderRecursive(); + */ + public function registerPostDataLoader($control) + { + $id=is_string($control)?$control:$control->getUniqueID(); + $this->_postDataLoaders[$id] = true; + } + + /** + * Get a list of IDs of controls that are enabled and require post data. + * @return array list of IDs implementing IPostBackDataHandler + */ + public function getPostDataLoaders() + { + return array_keys($this->_postDataLoaders); + } + + /** + * @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; + $this->registerPostDataLoader($id); + $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()); + } +} + +/** + * IPageStatePersister interface. + * + * IPageStatePersister interface is required for all page state persister + * classes. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @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(Prado::serialize($data)); + else + $str=Prado::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 Prado::unserialize($str); + } + else + return Prado::unserialize($str); + } + return null; + } +} diff --git a/framework/Web/UI/TPageStatePersister.php b/framework/Web/UI/TPageStatePersister.php index 18590a77..183cde13 100644 --- a/framework/Web/UI/TPageStatePersister.php +++ b/framework/Web/UI/TPageStatePersister.php @@ -1,71 +1,71 @@ -<?php
-/**
- * TPageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TPageStatePersister class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TPageStatePersister class
- *
- * TPageStatePersister implements a page state persistent method based on
- * form hidden fields.
- *
- * Since page state can be very big for complex pages, consider using
- * alternative persisters, such as {@link TSessionPageStatePersister},
- * which store page state on the server side and thus reduce the network
- * traffic for transmitting bulky page state.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TPageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_page;
-
- /**
- * @return TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * Saves state in hidden fields.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
- }
-
- /**
- * Loads page state from hidden fields.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- return $data;
- else
- throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TPageStatePersister class + * + * TPageStatePersister implements a page state persistent method based on + * form hidden fields. + * + * Since page state can be very big for complex pages, consider using + * alternative persisters, such as {@link TSessionPageStatePersister}, + * which store page state on the server side and thus reduce the network + * traffic for transmitting bulky page state. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TPageStatePersister extends TComponent implements IPageStatePersister +{ + private $_page; + + /** + * @return TPage the page that this persister works for + */ + public function getPage() + { + return $this->_page; + } + + /** + * @param TPage the page that this persister works for + */ + public function setPage(TPage $page) + { + $this->_page=$page; + } + + /** + * Saves state in hidden fields. + * @param mixed state to be stored + */ + public function save($state) + { + $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state)); + } + + /** + * Loads page state from hidden fields. + * @return mixed the restored state + * @throws THttpException if page state is corrupted + */ + public function load() + { + if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null) + return $data; + else + throw new THttpException(400,'pagestatepersister_pagestate_corrupted'); + } +} + diff --git a/framework/Web/UI/TSessionPageStatePersister.php b/framework/Web/UI/TSessionPageStatePersister.php index 4c2537df..a6d26f7a 100644 --- a/framework/Web/UI/TSessionPageStatePersister.php +++ b/framework/Web/UI/TSessionPageStatePersister.php @@ -1,131 +1,131 @@ -<?php
-/**
- * TSessionPageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TSessionPageStatePersister class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TSessionPageStatePersister class
- *
- * TSessionPageStatePersister implements a page state persistent method based on
- * sessions. Page state are stored in user sessions and therefore, this persister
- * requires session to be started and available.
- *
- * TSessionPageStatePersister keeps limited number of history states in session,
- * mainly to preserve the precious server storage. The number is specified
- * by {@link setHistorySize HistorySize}, which defaults to 10.
- *
- * There are a couple of ways to use TSessionPageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TSessionPageStatePersister instance there.
- * Or one can configure the pages to use TSessionPageStatePersister in page configurations
- * as follows,
- * <code>
- * <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
- * </code>
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TSessionPageStatePersister, use
- * <code>
- * <pages>
- * <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
- * </pages>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1
- */
-class TSessionPageStatePersister extends TComponent implements IPageStatePersister
-{
- const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
- const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
-
- private $_page;
- private $_historySize=10;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return integer maximum number of page states that should be kept in session. Defaults to 10.
- */
- public function getHistorySize()
- {
- return $this->_historySize;
- }
-
- /**
- * @param integer maximum number of page states that should be kept in session
- * @throws TInvalidDataValueException if the number is smaller than 1.
- */
- public function setHistorySize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>0)
- $this->_historySize=$value;
- else
- throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
- }
- /**
- * Saves state in session.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $session=$this->_page->getSession();
- $session->open();
- $data=serialize($state);
- $timestamp=(string)microtime(true);
- $key=self::STATE_SESSION_KEY.$timestamp;
- $session->add($key,$data);
- if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
- $queue=array();
- $queue[]=$key;
- if(count($queue)>$this->getHistorySize())
- {
- $expiredKey=array_shift($queue);
- $session->remove($expiredKey);
- }
- $session->add(self::QUEUE_SESSION_KEY,$queue);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from session.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $session=$this->_page->getSession();
- $session->open();
- $key=self::STATE_SESSION_KEY.$timestamp;
- if(($data=$session->itemAt($key))!==null)
- return unserialize($data);
- }
- throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * TSessionPageStatePersister class + * + * TSessionPageStatePersister implements a page state persistent method based on + * sessions. Page state are stored in user sessions and therefore, this persister + * requires session to be started and available. + * + * TSessionPageStatePersister keeps limited number of history states in session, + * mainly to preserve the precious server storage. The number is specified + * by {@link setHistorySize HistorySize}, which defaults to 10. + * + * There are a couple of ways to use TSessionPageStatePersister. + * One can override the page's {@link TPage::getStatePersister()} method and + * create a TSessionPageStatePersister instance there. + * Or one can configure the pages to use TSessionPageStatePersister in page configurations + * as follows, + * <code> + * <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" /> + * </code> + * The above configuration will affect the pages under the directory containing + * this configuration and all its subdirectories. + * To configure individual pages to use TSessionPageStatePersister, use + * <code> + * <pages> + * <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" /> + * </pages> + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.1 + */ +class TSessionPageStatePersister extends TComponent implements IPageStatePersister +{ + const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE'; + const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE'; + + private $_page; + private $_historySize=10; + + /** + * @param TPage the page that this persister works for + */ + public function getPage() + { + return $this->_page; + } + + /** + * @param TPage the page that this persister works for. + */ + public function setPage(TPage $page) + { + $this->_page=$page; + } + + /** + * @return integer maximum number of page states that should be kept in session. Defaults to 10. + */ + public function getHistorySize() + { + return $this->_historySize; + } + + /** + * @param integer maximum number of page states that should be kept in session + * @throws TInvalidDataValueException if the number is smaller than 1. + */ + public function setHistorySize($value) + { + if(($value=TPropertyValue::ensureInteger($value))>0) + $this->_historySize=$value; + else + throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid'); + } + /** + * Saves state in session. + * @param mixed state to be stored + */ + public function save($state) + { + $session=$this->_page->getSession(); + $session->open(); + $data=serialize($state); + $timestamp=(string)microtime(true); + $key=self::STATE_SESSION_KEY.$timestamp; + $session->add($key,$data); + if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null) + $queue=array(); + $queue[]=$key; + if(count($queue)>$this->getHistorySize()) + { + $expiredKey=array_shift($queue); + $session->remove($expiredKey); + } + $session->add(self::QUEUE_SESSION_KEY,$queue); + $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp)); + } + + /** + * Loads page state from session. + * @return mixed the restored state + * @throws THttpException if page state is corrupted + */ + public function load() + { + if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null) + { + $session=$this->_page->getSession(); + $session->open(); + $key=self::STATE_SESSION_KEY.$timestamp; + if(($data=$session->itemAt($key))!==null) + return unserialize($data); + } + throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted'); + } +} + diff --git a/framework/Web/UI/TTemplateControl.php b/framework/Web/UI/TTemplateControl.php index 400c1059..9b26728d 100644 --- a/framework/Web/UI/TTemplateControl.php +++ b/framework/Web/UI/TTemplateControl.php @@ -1,243 +1,243 @@ -<?php
-/**
- * TTemplateControl class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTemplateControl class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TCompositeControl class
- */
-Prado::using('System.Web.UI.TCompositeControl');
-
-/**
- * TTemplateControl class.
- * TTemplateControl is the base class for all controls that use templates.
- * By default, a control template is assumed to be in a file under the same
- * directory with the control class file. They have the same file name and
- * different extension name. For template file, the extension name is ".tpl".
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateControl extends TCompositeControl
-{
- /**
- * template file extension.
- */
- const EXT_TEMPLATE='.tpl';
-
- /**
- * @var ITemplate the parsed template structure shared by the same control class
- */
- private static $_template=array();
- /**
- * @var ITemplate the parsed template structure specific for this control instance
- */
- private $_localTemplate=null;
- /**
- * @var TTemplateControl the master control if any
- */
- private $_master=null;
- /**
- * @var string master control class name
- */
- private $_masterClass='';
- /**
- * @var array list of TContent controls
- */
- private $_contents=array();
- /**
- * @var array list of TContentPlaceHolder controls
- */
- private $_placeholders=array();
-
- /**
- * Returns the template object associated with this control object.
- * @return ITemplate|null the parsed template, null if none
- */
- public function getTemplate()
- {
- if($this->_localTemplate===null)
- {
- $class=get_class($this);
- if(!isset(self::$_template[$class]))
- self::$_template[$class]=$this->loadTemplate();
- return self::$_template[$class];
- }
- else
- return $this->_localTemplate;
- }
-
- /**
- * Sets the parsed template.
- * Note, the template will be applied to the whole control class.
- * This method should only be used by framework and control developers.
- * @param ITemplate the parsed template
- */
- public function setTemplate($value)
- {
- $this->_localTemplate=$value;
- }
-
- /**
- * @return boolean whether this control is a source template control.
- * A source template control loads its template from external storage,
- * such as file, db, rather than from within another template.
- */
- public function getIsSourceTemplateControl()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getIsSourceTemplate();
- else
- return false;
- }
-
- /**
- * @return string the directory containing the template. Empty if no template available.
- */
- public function getTemplateDirectory()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getContextPath();
- else
- return '';
- }
-
- /**
- * Loads the template associated with this control class.
- * @return ITemplate the parsed template structure
- */
- protected function loadTemplate()
- {
- Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
- $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
- return $template;
- }
-
- /**
- * Creates child controls.
- * This method is overridden to load and instantiate control template.
- * This method should only be used by framework and control developers.
- */
- public function createChildControls()
- {
- if($tpl=$this->getTemplate())
- {
- foreach($tpl->getDirective() as $name=>$value)
- {
- if(is_string($value))
- $this->setSubProperty($name,$value);
- else
- throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
- }
- $tpl->instantiateIn($this);
- }
- }
-
- /**
- * Registers a content control.
- * @param string ID of the content
- * @param TContent
- */
- public function registerContent($id,TContent $object)
- {
- if(isset($this->_contents[$id]))
- throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
- else
- $this->_contents[$id]=$object;
- }
-
- /**
- * Registers a content placeholder to this template control.
- * This method should only be used by framework and control developers.
- * @param string placeholder ID
- * @param TContentPlaceHolder placeholder control
- */
- public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
- {
- if(isset($this->_placeholders[$id]))
- throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
- else
- $this->_placeholders[$id]=$object;
- }
-
- /**
- * @return string master class name (in namespace form)
- */
- public function getMasterClass()
- {
- return $this->_masterClass;
- }
-
- /**
- * @param string master control class name (in namespace form)
- */
- public function setMasterClass($value)
- {
- $this->_masterClass=$value;
- }
-
- /**
- * @return TTemplateControl|null master control associated with this control, null if none
- */
- public function getMaster()
- {
- return $this->_master;
- }
-
- /**
- * Injects all content controls (and their children) to the corresponding content placeholders.
- * This method should only be used by framework and control developers.
- * @param string ID of the content control
- * @param TContent the content to be injected
- */
- public function injectContent($id,$content)
- {
- if(isset($this->_placeholders[$id]))
- {
- $placeholder=$this->_placeholders[$id];
- $controls=$placeholder->getParent()->getControls();
- $loc=$controls->remove($placeholder);
- $controls->insertAt($loc,$content);
- }
- else
- throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
- }
-
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first,
- * and if master class is set, master will be applied.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->_masterClass!=='')
- {
- $master=Prado::createComponent($this->_masterClass);
- if(!($master instanceof TTemplateControl))
- throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
- $this->_master=$master;
- $this->getControls()->clear();
- $this->getControls()->add($master);
- $master->ensureChildControls();
- foreach($this->_contents as $id=>$content)
- $master->injectContent($id,$content);
- }
- else if(!empty($this->_contents))
- throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * Includes TCompositeControl class + */ +Prado::using('System.Web.UI.TCompositeControl'); + +/** + * TTemplateControl class. + * TTemplateControl is the base class for all controls that use templates. + * By default, a control template is assumed to be in a file under the same + * directory with the control class file. They have the same file name and + * different extension name. For template file, the extension name is ".tpl". + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TTemplateControl extends TCompositeControl +{ + /** + * template file extension. + */ + const EXT_TEMPLATE='.tpl'; + + /** + * @var ITemplate the parsed template structure shared by the same control class + */ + private static $_template=array(); + /** + * @var ITemplate the parsed template structure specific for this control instance + */ + private $_localTemplate=null; + /** + * @var TTemplateControl the master control if any + */ + private $_master=null; + /** + * @var string master control class name + */ + private $_masterClass=''; + /** + * @var array list of TContent controls + */ + private $_contents=array(); + /** + * @var array list of TContentPlaceHolder controls + */ + private $_placeholders=array(); + + /** + * Returns the template object associated with this control object. + * @return ITemplate|null the parsed template, null if none + */ + public function getTemplate() + { + if($this->_localTemplate===null) + { + $class=get_class($this); + if(!isset(self::$_template[$class])) + self::$_template[$class]=$this->loadTemplate(); + return self::$_template[$class]; + } + else + return $this->_localTemplate; + } + + /** + * Sets the parsed template. + * Note, the template will be applied to the whole control class. + * This method should only be used by framework and control developers. + * @param ITemplate the parsed template + */ + public function setTemplate($value) + { + $this->_localTemplate=$value; + } + + /** + * @return boolean whether this control is a source template control. + * A source template control loads its template from external storage, + * such as file, db, rather than from within another template. + */ + public function getIsSourceTemplateControl() + { + if(($template=$this->getTemplate())!==null) + return $template->getIsSourceTemplate(); + else + return false; + } + + /** + * @return string the directory containing the template. Empty if no template available. + */ + public function getTemplateDirectory() + { + if(($template=$this->getTemplate())!==null) + return $template->getContextPath(); + else + return ''; + } + + /** + * Loads the template associated with this control class. + * @return ITemplate the parsed template structure + */ + protected function loadTemplate() + { + Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl'); + $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this)); + return $template; + } + + /** + * Creates child controls. + * This method is overridden to load and instantiate control template. + * This method should only be used by framework and control developers. + */ + public function createChildControls() + { + if($tpl=$this->getTemplate()) + { + foreach($tpl->getDirective() as $name=>$value) + { + if(is_string($value)) + $this->setSubProperty($name,$value); + else + throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name); + } + $tpl->instantiateIn($this); + } + } + + /** + * Registers a content control. + * @param string ID of the content + * @param TContent + */ + public function registerContent($id,TContent $object) + { + if(isset($this->_contents[$id])) + throw new TConfigurationException('templatecontrol_contentid_duplicated',$id); + else + $this->_contents[$id]=$object; + } + + /** + * Registers a content placeholder to this template control. + * This method should only be used by framework and control developers. + * @param string placeholder ID + * @param TContentPlaceHolder placeholder control + */ + public function registerContentPlaceHolder($id,TContentPlaceHolder $object) + { + if(isset($this->_placeholders[$id])) + throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id); + else + $this->_placeholders[$id]=$object; + } + + /** + * @return string master class name (in namespace form) + */ + public function getMasterClass() + { + return $this->_masterClass; + } + + /** + * @param string master control class name (in namespace form) + */ + public function setMasterClass($value) + { + $this->_masterClass=$value; + } + + /** + * @return TTemplateControl|null master control associated with this control, null if none + */ + public function getMaster() + { + return $this->_master; + } + + /** + * Injects all content controls (and their children) to the corresponding content placeholders. + * This method should only be used by framework and control developers. + * @param string ID of the content control + * @param TContent the content to be injected + */ + public function injectContent($id,$content) + { + if(isset($this->_placeholders[$id])) + { + $placeholder=$this->_placeholders[$id]; + $controls=$placeholder->getParent()->getControls(); + $loc=$controls->remove($placeholder); + $controls->insertAt($loc,$content); + } + else + throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id); + } + + /** + * Performs the OnInit step for the control and all its child controls. + * This method overrides the parent implementation + * by ensuring child controls are created first, + * and if master class is set, master will be applied. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + if($this->_masterClass!=='') + { + $master=Prado::createComponent($this->_masterClass); + if(!($master instanceof TTemplateControl)) + throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid'); + $this->_master=$master; + $this->getControls()->clear(); + $this->getControls()->add($master); + $master->ensureChildControls(); + foreach($this->_contents as $id=>$content) + $master->injectContent($id,$content); + } + else if(!empty($this->_contents)) + throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this)); + parent::initRecursive($namingContainer); + } +} + diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php index 4d17806b..f884cd65 100644 --- a/framework/Web/UI/TTemplateManager.php +++ b/framework/Web/UI/TTemplateManager.php @@ -1,1075 +1,1075 @@ -<?php
-/**
- * TTemplateManager and TTemplate class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TOutputCache class file
- */
-Prado::using('System.Web.UI.WebControls.TOutputCache');
-
-/**
- * TTemplateManager class
- *
- * TTemplateManager manages the loading and parsing of control templates.
- *
- * There are two ways of loading a template, either by the associated template
- * control class name, or the template file name.
- * The former is via calling {@link getTemplateByClassName}, which tries to
- * locate the corresponding template file under the directory containing
- * the class file. The name of the template file is the class name with
- * the extension '.tpl'. To load a template from a template file path,
- * call {@link getTemplateByFileName}.
- *
- * By default, TTemplateManager is registered with {@link TPageService} as the
- * template manager module that can be accessed via {@link TPageService::getTemplateManager()}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateManager extends TModule
-{
- /**
- * Template file extension
- */
- const TEMPLATE_FILE_EXT='.tpl';
- /**
- * Prefix of the cache variable name for storing parsed templates
- */
- const TEMPLATE_CACHE_PREFIX='prado:template:';
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * It starts output buffer if it is enabled.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- $this->getService()->setTemplateManager($this);
- }
-
- /**
- * Loads the template corresponding to the specified class name.
- * @return ITemplate template for the class name, null if template doesn't exist.
- */
- public function getTemplateByClassName($className)
- {
- $class=new ReflectionClass($className);
- $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
- return $this->getTemplateByFileName($tplFile);
- }
-
- /**
- * Loads the template from the specified file.
- * @return ITemplate template parsed from the specified file, null if the file doesn't exist.
- */
- public function getTemplateByFileName($fileName)
- {
- if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
- {
- Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager');
- if(($cache=$this->getApplication()->getCache())===null)
- return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- else
- {
- $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
- if(is_array($array))
- {
- list($template,$timestamps)=$array;
- if($this->getApplication()->getMode()===TApplicationMode::Performance)
- return $template;
- $cacheValid=true;
- foreach($timestamps as $tplFile=>$timestamp)
- {
- if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
- {
- $cacheValid=false;
- break;
- }
- }
- if($cacheValid)
- return $template;
- }
- $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- $includedFiles=$template->getIncludedFiles();
- $timestamps=array();
- $timestamps[$fileName]=filemtime($fileName);
- foreach($includedFiles as $includedFile)
- $timestamps[$includedFile]=filemtime($includedFile);
- $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
- return $template;
- }
- }
- else
- return null;
- }
-
- /**
- * Finds a localized template file.
- * @param string template file.
- * @return string|null a localized template file if found, null otherwise.
- */
- protected function getLocalizedTemplate($filename)
- {
- if(($app=$this->getApplication()->getGlobalization(false))===null)
- return is_file($filename)?$filename:null;
- foreach($app->getLocalizedResource($filename) as $file)
- {
- if(($file=realpath($file))!==false && is_file($file))
- return $file;
- }
- return null;
- }
-}
-
-/**
- * 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 <prop:AttributeName> 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
- * <prop:MainProperty SubProperty1="Value1" SubProperty2="Value2" .../>
- * - 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 <!-- comments -->, which will be treated as text strings.
- * The latter is in the format of <!-- comments --!>, 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 <qiang.xue@gmail.com>
- * @version $Id$
- * @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
- * '<prop:([\w\.]+)((?:\s*[\w\.]+=\'.*?\'|\s*[\w\.]+=".*?"|\s*[\w\.]+=<%.*?%>)*)\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*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\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,'<com:')===0) // opening component tag
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$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,'</com:')===0) // closing component tag
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$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',"</com:$type>");
-
- $name=array_pop($stack);
- if($name!==$type)
- {
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- 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,"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,'<prop:')===0) // opening property
- {
- if(strrpos($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,'</prop:')===0) // closing property
- {
- $prop=strtolower($match[3][0]);
- if(empty($stack))
- throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
- $name=array_pop($stack);
- if($name!=='@'.$prop)
- {
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- 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,'<!--')===0) // comments
- {
- if($expectPropEnd)
- throw new TConfigurationException('template_comments_forbidden');
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- }
- else
- throw new TConfigurationException('template_matching_unexpected',$match);
- }
- if(!empty($stack))
- {
- $name=array_pop($stack);
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- if($textStart<strlen($input))
- $tpl[$c++]=array($container,substr($input,$textStart));
- }
- catch(Exception $e)
- {
- if(($e instanceof TException) && ($e instanceof TTemplateException))
- throw $e;
- if($matchEnd===0)
- $line=$this->_startingLine+1;
- else
- $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
- $this->handleException($e,$line,$input);
- }
-
- if($this->_directive===null)
- $this->_directive=array();
-
- // optimization by merging consecutive strings, expressions, statements and bindings
- $objects=array();
- $parent=null;
- $merged=array();
- foreach($tpl as $id=>$object)
- {
- if(isset($object[2]) || $object[0]!==$parent)
- {
- if($parent!==null)
- {
- if(count($merged[1])===1 && is_string($merged[1][0]))
- $objects[$id-1]=array($merged[0],$merged[1][0]);
- else
- $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
- }
- if(isset($object[2]))
- {
- $parent=null;
- $objects[$id]=$object;
- }
- else
- {
- $parent=$object[0];
- $merged=array($parent,array($object[1]));
- }
- }
- else
- $merged[1][]=$object[1];
- }
- if($parent!==null)
- {
- if(count($merged[1])===1 && is_string($merged[1][0]))
- $objects[$id]=array($merged[0],$merged[1][0]);
- else
- $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
- }
- $tpl=$objects;
- return $objects;
- }
-
- /**
- * Parses the attributes of a tag from a string.
- * @param string the string to be parsed.
- * @return array attribute values indexed by names.
- */
- protected function parseAttributes($str,$offset)
- {
- if($str==='')
- return array();
- $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
- $attributes=array();
- $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
- for($i=0;$i<$n;++$i)
- {
- $match=&$matches[$i];
- $name=strtolower($match[1][0]);
- if(isset($attributes[$name]))
- throw new TConfigurationException('template_property_duplicated',$name);
- $value=$match[2][0];
- if(substr($name,-8,8)==='template')
- {
- if($value[0]==='\'' || $value[0]==='"')
- $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
- else
- $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
- }
- else
- {
- if($value[0]==='\'' || $value[0]==='"')
- $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
- else
- $attributes[$name]=$this->parseAttribute($value);
- }
- }
- return $attributes;
- }
-
- protected function parseTemplateProperty($content,$offset)
- {
- $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
- return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
- }
-
- /**
- * Parses a single attribute.
- * @param string the string to be parsed.
- * @return array attribute initialization
- */
- protected function parseAttribute($value)
- {
- if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
- {
- $isDataBind=false;
- $textStart=0;
- $expr='';
- for($i=0;$i<$n;++$i)
- {
- $match=$matches[0][$i];
- $token=$match[0];
- $offset=$match[1];
- $length=strlen($token);
- if($token[2]==='#')
- $isDataBind=true;
- if($offset>$textStart)
- $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
- $expr.='.('.substr($token,3,$length-5).')';
- $textStart=$offset+$length;
- }
- $length=strlen($value);
- if($length>$textStart)
- $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
- if($isDataBind)
- return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
- else
- return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
- }
- else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
- {
- $value=$matches[1];
- if($value[2]==='~')
- return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
- elseif($value[2]==='[')
- return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
- elseif($value[2]==='$')
- return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
- elseif($value[2]==='/') {
- $literal = trim(substr($value,3,strlen($value)-5));
- return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'");
- }
- }
- else
- return $value;
- }
-
- protected function validateAttributes($type,$attributes)
- {
- Prado::using($type);
- if(($pos=strrpos($type,'.'))!==false)
- $className=substr($type,$pos+1);
- else
- $className=$type;
- $class=new ReflectionClass($className);
- if(is_subclass_of($className,'TControl') || $className==='TControl')
- {
- foreach($attributes as $name=>$att)
- {
- if(($pos=strpos($name,'.'))!==false)
- {
- // a subproperty, so the first segment must be readable
- $subname=substr($name,0,$pos);
- if(!$class->hasMethod('get'.$subname))
- throw new TConfigurationException('template_property_unknown',$type,$subname);
- }
- else if(strncasecmp($name,'on',2)===0)
- {
- // an event
- if(!$class->hasMethod($name))
- throw new TConfigurationException('template_event_unknown',$type,$name);
- else if(!is_string($att))
- throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
- }
- else
- {
- // a simple property
- if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name)) )
- {
- if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
- throw new TConfigurationException('template_property_readonly',$type,$name);
- else
- throw new TConfigurationException('template_property_unknown',$type,$name);
- }
- else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
- {
- if(strcasecmp($name,'id')===0)
- throw new TConfigurationException('template_controlid_invalid',$type);
- else if(strcasecmp($name,'skinid')===0)
- throw new TConfigurationException('template_controlskinid_invalid',$type);
- }
- }
- }
- }
- else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
- {
- foreach($attributes as $name=>$att)
- {
- if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
- throw new TConfigurationException('template_databind_forbidden',$type,$name);
- if(($pos=strpos($name,'.'))!==false)
- {
- // a subproperty, so the first segment must be readable
- $subname=substr($name,0,$pos);
- if(!$class->hasMethod('get'.$subname))
- throw new TConfigurationException('template_property_unknown',$type,$subname);
- }
- else if(strncasecmp($name,'on',2)===0)
- throw new TConfigurationException('template_event_forbidden',$type,$name);
- else
- {
- // id is still alowed for TComponent, even if id property doesn't exist
- if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
- {
- if($class->hasMethod('get'.$name))
- throw new TConfigurationException('template_property_readonly',$type,$name);
- else
- throw new TConfigurationException('template_property_unknown',$type,$name);
- }
- }
- }
- }
- else
- throw new TConfigurationException('template_component_required',$type);
- }
-
- /**
- * @return array list of included external template files
- */
- public function getIncludedFiles()
- {
- return $this->_includedFiles;
- }
-
- /**
- * Handles template parsing exception.
- * This method rethrows the exception caught during template parsing.
- * It adjusts the error location by giving out correct error line number and source file.
- * @param Exception template exception
- * @param int line number
- * @param string template string if no source file is used
- */
- protected function handleException($e,$line,$input=null)
- {
- $srcFile=$this->_tplFile;
-
- if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name
- {
- for($i=$n-1;$i>=0;--$i)
- {
- if($this->_includeAtLine[$i]<=$line)
- {
- if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
- {
- $line=$line-$this->_includeAtLine[$i]+1;
- $srcFile=$this->_includedFiles[$i];
- break;
- }
- else
- $line=$line-$this->_includeLines[$i]+1;
- }
- }
- }
- $exception=new TTemplateException('template_format_invalid',$e->getMessage());
- $exception->setLineNumber($line);
- if(!empty($srcFile))
- $exception->setTemplateFile($srcFile);
- else
- $exception->setTemplateSource($input);
- throw $exception;
- }
-
- /**
- * Preprocesses the template string by including external templates
- * @param string template string
- * @return string expanded template string
- */
- protected function preprocess($input)
- {
- if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
- {
- for($i=0;$i<$n;++$i)
- {
- $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
- if($filePath!==null && is_file($filePath))
- $this->_includedFiles[]=$filePath;
- else
- {
- $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
- $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
- }
- }
- $base=0;
- for($i=0;$i<$n;++$i)
- {
- $ext=file_get_contents($this->_includedFiles[$i]);
- $length=strlen($matches[$i][0][0]);
- $offset=$base+$matches[$i][0][1];
- $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
- $this->_includeLines[$i]=count(explode("\n",$ext));
- $input=substr_replace($input,$ext,$offset,$length);
- $base+=strlen($ext)-$length;
- }
- }
-
- return $input;
- }
-}
-
+<?php +/** + * TTemplateManager and TTemplate class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * Includes TOutputCache class file + */ +Prado::using('System.Web.UI.WebControls.TOutputCache'); + +/** + * TTemplateManager class + * + * TTemplateManager manages the loading and parsing of control templates. + * + * There are two ways of loading a template, either by the associated template + * control class name, or the template file name. + * The former is via calling {@link getTemplateByClassName}, which tries to + * locate the corresponding template file under the directory containing + * the class file. The name of the template file is the class name with + * the extension '.tpl'. To load a template from a template file path, + * call {@link getTemplateByFileName}. + * + * By default, TTemplateManager is registered with {@link TPageService} as the + * template manager module that can be accessed via {@link TPageService::getTemplateManager()}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TTemplateManager extends TModule +{ + /** + * Template file extension + */ + const TEMPLATE_FILE_EXT='.tpl'; + /** + * Prefix of the cache variable name for storing parsed templates + */ + const TEMPLATE_CACHE_PREFIX='prado:template:'; + + /** + * Initializes the module. + * This method is required by IModule and is invoked by application. + * It starts output buffer if it is enabled. + * @param TXmlElement module configuration + */ + public function init($config) + { + $this->getService()->setTemplateManager($this); + } + + /** + * Loads the template corresponding to the specified class name. + * @return ITemplate template for the class name, null if template doesn't exist. + */ + public function getTemplateByClassName($className) + { + $class=new ReflectionClass($className); + $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT; + return $this->getTemplateByFileName($tplFile); + } + + /** + * Loads the template from the specified file. + * @return ITemplate template parsed from the specified file, null if the file doesn't exist. + */ + public function getTemplateByFileName($fileName) + { + if(($fileName=$this->getLocalizedTemplate($fileName))!==null) + { + Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager'); + if(($cache=$this->getApplication()->getCache())===null) + return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); + else + { + $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName); + if(is_array($array)) + { + list($template,$timestamps)=$array; + if($this->getApplication()->getMode()===TApplicationMode::Performance) + return $template; + $cacheValid=true; + foreach($timestamps as $tplFile=>$timestamp) + { + if(!is_file($tplFile) || filemtime($tplFile)>$timestamp) + { + $cacheValid=false; + break; + } + } + if($cacheValid) + return $template; + } + $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); + $includedFiles=$template->getIncludedFiles(); + $timestamps=array(); + $timestamps[$fileName]=filemtime($fileName); + foreach($includedFiles as $includedFile) + $timestamps[$includedFile]=filemtime($includedFile); + $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps)); + return $template; + } + } + else + return null; + } + + /** + * Finds a localized template file. + * @param string template file. + * @return string|null a localized template file if found, null otherwise. + */ + protected function getLocalizedTemplate($filename) + { + if(($app=$this->getApplication()->getGlobalization(false))===null) + return is_file($filename)?$filename:null; + foreach($app->getLocalizedResource($filename) as $file) + { + if(($file=realpath($file))!==false && is_file($file)) + return $file; + } + return null; + } +} + +/** + * 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 <prop:AttributeName> 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 + * <prop:MainProperty SubProperty1="Value1" SubProperty2="Value2" .../> + * - 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 <!-- comments -->, which will be treated as text strings. + * The latter is in the format of <!-- comments --!>, 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 <qiang.xue@gmail.com> + * @version $Id$ + * @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 + * '<prop:([\w\.]+)((?:\s*[\w\.]+=\'.*?\'|\s*[\w\.]+=".*?"|\s*[\w\.]+=<%.*?%>)*)\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*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\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,'<com:')===0) // opening component tag + { + if($expectPropEnd) + continue; + if($matchStart>$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,'</com:')===0) // closing component tag + { + if($expectPropEnd) + continue; + if($matchStart>$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',"</com:$type>"); + + $name=array_pop($stack); + if($name!==$type) + { + $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; + 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,"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,'<prop:')===0) // opening property + { + if(strrpos($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,'</prop:')===0) // closing property + { + $prop=strtolower($match[3][0]); + if(empty($stack)) + throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>"); + $name=array_pop($stack); + if($name!=='@'.$prop) + { + $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; + 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,'<!--')===0) // comments + { + if($expectPropEnd) + throw new TConfigurationException('template_comments_forbidden'); + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + } + else + throw new TConfigurationException('template_matching_unexpected',$match); + } + if(!empty($stack)) + { + $name=array_pop($stack); + $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>"; + throw new TConfigurationException('template_closingtag_expected',$tag); + } + if($textStart<strlen($input)) + $tpl[$c++]=array($container,substr($input,$textStart)); + } + catch(Exception $e) + { + if(($e instanceof TException) && ($e instanceof TTemplateException)) + throw $e; + if($matchEnd===0) + $line=$this->_startingLine+1; + else + $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1))); + $this->handleException($e,$line,$input); + } + + if($this->_directive===null) + $this->_directive=array(); + + // optimization by merging consecutive strings, expressions, statements and bindings + $objects=array(); + $parent=null; + $merged=array(); + foreach($tpl as $id=>$object) + { + if(isset($object[2]) || $object[0]!==$parent) + { + if($parent!==null) + { + if(count($merged[1])===1 && is_string($merged[1][0])) + $objects[$id-1]=array($merged[0],$merged[1][0]); + else + $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1])); + } + if(isset($object[2])) + { + $parent=null; + $objects[$id]=$object; + } + else + { + $parent=$object[0]; + $merged=array($parent,array($object[1])); + } + } + else + $merged[1][]=$object[1]; + } + if($parent!==null) + { + if(count($merged[1])===1 && is_string($merged[1][0])) + $objects[$id]=array($merged[0],$merged[1][0]); + else + $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1])); + } + $tpl=$objects; + return $objects; + } + + /** + * Parses the attributes of a tag from a string. + * @param string the string to be parsed. + * @return array attribute values indexed by names. + */ + protected function parseAttributes($str,$offset) + { + if($str==='') + return array(); + $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS'; + $attributes=array(); + $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + for($i=0;$i<$n;++$i) + { + $match=&$matches[$i]; + $name=strtolower($match[1][0]); + if(isset($attributes[$name])) + throw new TConfigurationException('template_property_duplicated',$name); + $value=$match[2][0]; + if(substr($name,-8,8)==='template') + { + if($value[0]==='\'' || $value[0]==='"') + $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1); + else + $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]); + } + else + { + if($value[0]==='\'' || $value[0]==='"') + $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2)); + else + $attributes[$name]=$this->parseAttribute($value); + } + } + return $attributes; + } + + protected function parseTemplateProperty($content,$offset) + { + $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1; + return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false)); + } + + /** + * Parses a single attribute. + * @param string the string to be parsed. + * @return array attribute initialization + */ + protected function parseAttribute($value) + { + if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0) + { + $isDataBind=false; + $textStart=0; + $expr=''; + for($i=0;$i<$n;++$i) + { + $match=$matches[0][$i]; + $token=$match[0]; + $offset=$match[1]; + $length=strlen($token); + if($token[2]==='#') + $isDataBind=true; + if($offset>$textStart) + $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'"; + $expr.='.('.substr($token,3,$length-5).')'; + $textStart=$offset+$length; + } + $length=strlen($value); + if($length>$textStart) + $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'"; + if($isDataBind) + return array(self::CONFIG_DATABIND,ltrim($expr,'.')); + else + return array(self::CONFIG_EXPRESSION,ltrim($expr,'.')); + } + else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value) + { + $value=$matches[1]; + if($value[2]==='~') + return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5))); + elseif($value[2]==='[') + return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6))); + elseif($value[2]==='$') + return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5))); + elseif($value[2]==='/') { + $literal = trim(substr($value,3,strlen($value)-5)); + return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"); + } + } + else + return $value; + } + + protected function validateAttributes($type,$attributes) + { + Prado::using($type); + if(($pos=strrpos($type,'.'))!==false) + $className=substr($type,$pos+1); + else + $className=$type; + $class=new ReflectionClass($className); + if(is_subclass_of($className,'TControl') || $className==='TControl') + { + foreach($attributes as $name=>$att) + { + if(($pos=strpos($name,'.'))!==false) + { + // a subproperty, so the first segment must be readable + $subname=substr($name,0,$pos); + if(!$class->hasMethod('get'.$subname)) + throw new TConfigurationException('template_property_unknown',$type,$subname); + } + else if(strncasecmp($name,'on',2)===0) + { + // an event + if(!$class->hasMethod($name)) + throw new TConfigurationException('template_event_unknown',$type,$name); + else if(!is_string($att)) + throw new TConfigurationException('template_eventhandler_invalid',$type,$name); + } + else + { + // a simple property + if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name)) ) + { + if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name)) + throw new TConfigurationException('template_property_readonly',$type,$name); + else + throw new TConfigurationException('template_property_unknown',$type,$name); + } + else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION) + { + if(strcasecmp($name,'id')===0) + throw new TConfigurationException('template_controlid_invalid',$type); + else if(strcasecmp($name,'skinid')===0) + throw new TConfigurationException('template_controlskinid_invalid',$type); + } + } + } + } + else if(is_subclass_of($className,'TComponent') || $className==='TComponent') + { + foreach($attributes as $name=>$att) + { + if(is_array($att) && ($att[0]===self::CONFIG_DATABIND)) + throw new TConfigurationException('template_databind_forbidden',$type,$name); + if(($pos=strpos($name,'.'))!==false) + { + // a subproperty, so the first segment must be readable + $subname=substr($name,0,$pos); + if(!$class->hasMethod('get'.$subname)) + throw new TConfigurationException('template_property_unknown',$type,$subname); + } + else if(strncasecmp($name,'on',2)===0) + throw new TConfigurationException('template_event_forbidden',$type,$name); + else + { + // id is still alowed for TComponent, even if id property doesn't exist + if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name)) + { + if($class->hasMethod('get'.$name)) + throw new TConfigurationException('template_property_readonly',$type,$name); + else + throw new TConfigurationException('template_property_unknown',$type,$name); + } + } + } + } + else + throw new TConfigurationException('template_component_required',$type); + } + + /** + * @return array list of included external template files + */ + public function getIncludedFiles() + { + return $this->_includedFiles; + } + + /** + * Handles template parsing exception. + * This method rethrows the exception caught during template parsing. + * It adjusts the error location by giving out correct error line number and source file. + * @param Exception template exception + * @param int line number + * @param string template string if no source file is used + */ + protected function handleException($e,$line,$input=null) + { + $srcFile=$this->_tplFile; + + if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name + { + for($i=$n-1;$i>=0;--$i) + { + if($this->_includeAtLine[$i]<=$line) + { + if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i]) + { + $line=$line-$this->_includeAtLine[$i]+1; + $srcFile=$this->_includedFiles[$i]; + break; + } + else + $line=$line-$this->_includeLines[$i]+1; + } + } + } + $exception=new TTemplateException('template_format_invalid',$e->getMessage()); + $exception->setLineNumber($line); + if(!empty($srcFile)) + $exception->setTemplateFile($srcFile); + else + $exception->setTemplateSource($input); + throw $exception; + } + + /** + * Preprocesses the template string by including external templates + * @param string template string + * @return string expanded template string + */ + protected function preprocess($input) + { + if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE)) + { + for($i=0;$i<$n;++$i) + { + $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT); + if($filePath!==null && is_file($filePath)) + $this->_includedFiles[]=$filePath; + else + { + $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1))); + $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input); + } + } + $base=0; + for($i=0;$i<$n;++$i) + { + $ext=file_get_contents($this->_includedFiles[$i]); + $length=strlen($matches[$i][0][0]); + $offset=$base+$matches[$i][0][1]; + $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset))); + $this->_includeLines[$i]=count(explode("\n",$ext)); + $input=substr_replace($input,$ext,$offset,$length); + $base+=strlen($ext)-$length; + } + } + + return $input; + } +} + diff --git a/framework/Web/UI/TThemeManager.php b/framework/Web/UI/TThemeManager.php index 57ab21ad..0d6befd4 100644 --- a/framework/Web/UI/TThemeManager.php +++ b/framework/Web/UI/TThemeManager.php @@ -1,517 +1,517 @@ -<?php
-/**
- * TThemeManager class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-Prado::using('System.Web.Services.TPageService');
-
-/**
- * TThemeManager class
- *
- * TThemeManager manages the themes used in a Prado application.
- *
- * Themes are stored under the directory specified by the
- * {@link setBasePath BasePath} property. The themes can be accessed
- * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory
- * and all the files under that directory. The name of a theme is the name
- * of the corresponding subdirectory.
- * By default, the base path of all themes is a directory named "themes"
- * under the directory containing the application entry script.
- * To get a theme (normally you do not need to), call {@link getTheme}.
- *
- * TThemeManager may be configured within page service tag in application
- * configuration file as follows,
- * <module id="themes" class="System.Web.UI.TThemeManager"
- * BasePath="Application.themes" BaseUrl="/themes" />
- * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
- * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TThemeManager extends TModule
-{
- /**
- * default themes base path
- */
- const DEFAULT_BASEPATH='themes';
-
- /**
- * default theme class
- */
- const DEFAULT_THEMECLASS = 'TTheme';
-
- /**
- * @var string
- */
- private $_themeClass=self::DEFAULT_THEMECLASS;
-
- /**
- * @var boolean whether this module has been initialized
- */
- private $_initialized=false;
- /**
- * @var string the directory containing all themes
- */
- private $_basePath=null;
- /**
- * @var string the base URL for all themes
- */
- private $_baseUrl=null;
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- $this->_initialized=true;
- $service=$this->getService();
- if($service instanceof TPageService)
- $service->setThemeManager($this);
- else
- throw new TConfigurationException('thememanager_service_unavailable');
- }
-
- /**
- * @param string name of the theme to be retrieved
- * @return TTheme the theme retrieved
- */
- public function getTheme($name)
- {
- $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
- $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
- return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
- }
-
- /**
- * @param string|null $class Theme class name in namespace format
- */
- public function setThemeClass($class) {
- $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
- }
-
- /**
- * @return string Theme class name in namespace format. Defaults to {@link TThemeManager::DEFAULT_THEMECLASS DEFAULT_THEMECLASS}.
- */
- public function getThemeClass() {
- return $this->_themeClass;
- }
-
- /**
- * @return array list of available theme names
- */
- public function getAvailableThemes()
- {
- $themes=array();
- $basePath=$this->getBasePath();
- $folder=@opendir($basePath);
- while($file=@readdir($folder))
- {
- if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
- $themes[]=$file;
- }
- closedir($folder);
- return $themes;
- }
-
- /**
- * @return string the base path for all themes. It is returned as an absolute path.
- * @throws TConfigurationException if base path is not set and "themes" directory does not exist.
- */
- public function getBasePath()
- {
- if($this->_basePath===null)
- {
- $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
- if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
- throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
- $this->_basePath=$basePath;
- }
- return $this->_basePath;
- }
-
- /**
- * @param string the base path for all themes. It must be in the format of a namespace.
- * @throws TInvalidDataValueException if the base path is not a proper namespace.
- */
- public function setBasePath($value)
- {
- if($this->_initialized)
- throw new TInvalidOperationException('thememanager_basepath_unchangeable');
- else
- {
- $this->_basePath=Prado::getPathOfNamespace($value);
- if($this->_basePath===null || !is_dir($this->_basePath))
- throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
- }
- }
-
- /**
- * @return string the base URL for all themes.
- * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado.
- */
- public function getBaseUrl()
- {
- if($this->_baseUrl===null)
- {
- $appPath=dirname($this->getRequest()->getApplicationFilePath());
- $basePath=$this->getBasePath();
- if(strpos($basePath,$appPath)===false)
- throw new TConfigurationException('thememanager_baseurl_required');
- $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
- $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
- }
- return $this->_baseUrl;
- }
-
- /**
- * @param string the base URL for all themes.
- */
- public function setBaseUrl($value)
- {
- $this->_baseUrl=rtrim($value,'/');
- }
-}
-
-/**
- * TTheme class
- *
- * TTheme represents a particular theme. It is merely a collection of skins
- * that are applicable to the corresponding controls.
- *
- * Each theme is stored as a directory and files under that directory.
- * The theme name is the directory name. When TTheme is created, the files
- * whose name has the extension ".skin" are parsed and saved as controls skins.
- *
- * A skin is essentially a list of initial property values that are to be applied
- * to a control when the skin is applied.
- * Each type of control can have multiple skins identified by the SkinID.
- * If a skin does not have SkinID, it is the default skin that will be applied
- * to controls that do not specify particular SkinID.
- *
- * Whenever possible, TTheme will try to make use of available cache to save
- * the parsing time.
- *
- * To apply a theme to a particular control, call {@link applySkin}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTheme extends TApplicationComponent implements ITheme
-{
- /**
- * prefix for cache variable name used to store parsed themes
- */
- const THEME_CACHE_PREFIX='prado:theme:';
- /**
- * Extension name of skin files
- */
- const SKIN_FILE_EXT='.skin';
- /**
- * @var string theme path
- */
- private $_themePath;
- /**
- * @var string theme url
- */
- private $_themeUrl;
- /**
- * @var array list of skins for the theme
- */
- private $_skins=null;
- /**
- * @var string theme name
- */
- private $_name='';
- /**
- * @var array list of css files
- */
- private $_cssFiles=array();
- /**
- * @var array list of js files
- */
- private $_jsFiles=array();
-
- /**
- * Constructor.
- * @param string theme path
- * @param string theme URL
- * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
- */
- public function __construct($themePath,$themeUrl)
- {
- $this->_themeUrl=$themeUrl;
- $this->_themePath=realpath($themePath);
- $this->_name=basename($themePath);
- $cacheValid=false;
- // TODO: the following needs to be cleaned up (Qiang)
- if(($cache=$this->getApplication()->getCache())!==null)
- {
- $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
- if(is_array($array))
- {
- list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
- if($this->getApplication()->getMode()!==TApplicationMode::Performance)
- {
- if(($dir=opendir($themePath))===false)
- throw new TIOException('theme_path_inexistent',$themePath);
- $cacheValid=true;
- while(($file=readdir($dir))!==false)
- {
- if($file==='.' || $file==='..')
- continue;
- else if(basename($file,'.css')!==$file)
- $this->_cssFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,'.js')!==$file)
- $this->_jsFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
- {
- $cacheValid=false;
- break;
- }
- }
- closedir($dir);
- if($cacheValid)
- $this->_skins=$skins;
- }
- else
- {
- $cacheValid=true;
- $this->_cssFiles=$cssFiles;
- $this->_jsFiles=$jsFiles;
- $this->_skins=$skins;
- }
- }
- }
- if(!$cacheValid)
- {
- $this->_cssFiles=array();
- $this->_jsFiles=array();
- $this->_skins=array();
- if(($dir=opendir($themePath))===false)
- throw new TIOException('theme_path_inexistent',$themePath);
- while(($file=readdir($dir))!==false)
- {
- if($file==='.' || $file==='..')
- continue;
- else if(basename($file,'.css')!==$file)
- $this->_cssFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,'.js')!==$file)
- $this->_jsFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,self::SKIN_FILE_EXT)!==$file)
- {
- $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
- foreach($template->getItems() as $skin)
- {
- if(!isset($skin[2])) // a text string, ignored
- continue;
- else if($skin[0]!==-1)
- throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
- $type=$skin[1];
- $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
- unset($skin[2]['skinid']);
- if(isset($this->_skins[$type][$id]))
- throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
- /*
- foreach($skin[2] as $name=>$value)
- {
- if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER))
- throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
- }
- */
- $this->_skins[$type][$id]=$skin[2];
- }
- }
- }
- closedir($dir);
- sort($this->_cssFiles);
- sort($this->_jsFiles);
- if($cache!==null)
- $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
- }
- }
-
- /**
- * @return string theme name
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string theme name
- */
- protected function setName($value)
- {
- $this->_name = $value;
- }
-
- /**
- * @return string the URL to the theme folder (without ending slash)
- */
- public function getBaseUrl()
- {
- return $this->_themeUrl;
- }
-
- /**
- * @param string the URL to the theme folder
- */
- protected function setBaseUrl($value)
- {
- $this->_themeUrl=rtrim($value,'/');
- }
-
- /**
- * @return string the file path to the theme folder
- */
- public function getBasePath()
- {
- return $this->_themePath;
- }
-
- /**
- * @param string tthe file path to the theme folder
- */
- protected function setBasePath($value)
- {
- $this->_themePath=$value;
- }
-
- /**
- * @return array list of skins for the theme
- */
- public function getSkins()
- {
- return $this->_skins;
- }
-
- /**
- * @param array list of skins for the theme
- */
- protected function setSkins($value)
- {
- $this->_skins = $value;
- }
-
- /**
- * Applies the theme to a particular control.
- * The control's class name and SkinID value will be used to
- * identify which skin to be applied. If the control's SkinID is empty,
- * the default skin will be applied.
- * @param TControl the control to be applied with a skin
- * @return boolean if a skin is successfully applied
- * @throws TConfigurationException if any error happened during the skin application
- */
- public function applySkin($control)
- {
- $type=get_class($control);
- if(($id=$control->getSkinID())==='')
- $id=0;
- if(isset($this->_skins[$type][$id]))
- {
- foreach($this->_skins[$type][$id] as $name=>$value)
- {
- Prado::trace("Applying skin $name to $type",'System.Web.UI.TThemeManager');
- if(is_array($value))
- {
- switch($value[0])
- {
- case TTemplate::CONFIG_EXPRESSION:
- $value=$this->evaluateExpression($value[1]);
- break;
- case TTemplate::CONFIG_ASSET:
- $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
- break;
- case TTemplate::CONFIG_DATABIND:
- $control->bindProperty($name,$value[1]);
- break;
- case TTemplate::CONFIG_PARAMETER:
- $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case TTemplate::CONFIG_TEMPLATE:
- $control->setSubProperty($name,$value[1]);
- break;
- case TTemplate::CONFIG_LOCALIZATION:
- $control->setSubProperty($name,Prado::localize($value[1]));
- break;
- default:
- throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
- break;
- }
- }
- if(!is_array($value))
- {
- if(strpos($name,'.')===false) // is simple property or custom attribute
- {
- if($control->hasProperty($name))
- {
- if($control->canSetProperty($name))
- {
- $setter='set'.$name;
- $control->$setter($value);
- }
- else
- throw new TConfigurationException('theme_property_readonly',$type,$name);
- }
- else
- throw new TConfigurationException('theme_property_undefined',$type,$name);
- }
- else // complex property
- $control->setSubProperty($name,$value);
- }
- }
- return true;
- }
- else
- return false;
- }
-
- /**
- * @return array list of CSS files (URL) in the theme
- */
- public function getStyleSheetFiles()
- {
- return $this->_cssFiles;
- }
-
- /**
- * @param array list of CSS files (URL) in the theme
- */
- protected function setStyleSheetFiles($value)
- {
- $this->_cssFiles=$value;
- }
-
- /**
- * @return array list of Javascript files (URL) in the theme
- */
- public function getJavaScriptFiles()
- {
- return $this->_jsFiles;
- }
-
- /**
- * @param array list of Javascript files (URL) in the theme
- */
- protected function setJavaScriptFiles($value)
- {
- $this->_jsFiles=$value;
- }
-}
-
-?>
+<?php +/** + * TThemeManager class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +Prado::using('System.Web.Services.TPageService'); + +/** + * TThemeManager class + * + * TThemeManager manages the themes used in a Prado application. + * + * Themes are stored under the directory specified by the + * {@link setBasePath BasePath} property. The themes can be accessed + * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory + * and all the files under that directory. The name of a theme is the name + * of the corresponding subdirectory. + * By default, the base path of all themes is a directory named "themes" + * under the directory containing the application entry script. + * To get a theme (normally you do not need to), call {@link getTheme}. + * + * TThemeManager may be configured within page service tag in application + * configuration file as follows, + * <module id="themes" class="System.Web.UI.TThemeManager" + * BasePath="Application.themes" BaseUrl="/themes" /> + * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl} + * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TThemeManager extends TModule +{ + /** + * default themes base path + */ + const DEFAULT_BASEPATH='themes'; + + /** + * default theme class + */ + const DEFAULT_THEMECLASS = 'TTheme'; + + /** + * @var string + */ + private $_themeClass=self::DEFAULT_THEMECLASS; + + /** + * @var boolean whether this module has been initialized + */ + private $_initialized=false; + /** + * @var string the directory containing all themes + */ + private $_basePath=null; + /** + * @var string the base URL for all themes + */ + private $_baseUrl=null; + + /** + * Initializes the module. + * This method is required by IModule and is invoked by application. + * @param TXmlElement module configuration + */ + public function init($config) + { + $this->_initialized=true; + $service=$this->getService(); + if($service instanceof TPageService) + $service->setThemeManager($this); + else + throw new TConfigurationException('thememanager_service_unavailable'); + } + + /** + * @param string name of the theme to be retrieved + * @return TTheme the theme retrieved + */ + public function getTheme($name) + { + $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name; + $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name; + return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl); + } + + /** + * @param string|null $class Theme class name in namespace format + */ + public function setThemeClass($class) { + $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class; + } + + /** + * @return string Theme class name in namespace format. Defaults to {@link TThemeManager::DEFAULT_THEMECLASS DEFAULT_THEMECLASS}. + */ + public function getThemeClass() { + return $this->_themeClass; + } + + /** + * @return array list of available theme names + */ + public function getAvailableThemes() + { + $themes=array(); + $basePath=$this->getBasePath(); + $folder=@opendir($basePath); + while($file=@readdir($folder)) + { + if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file)) + $themes[]=$file; + } + closedir($folder); + return $themes; + } + + /** + * @return string the base path for all themes. It is returned as an absolute path. + * @throws TConfigurationException if base path is not set and "themes" directory does not exist. + */ + public function getBasePath() + { + if($this->_basePath===null) + { + $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH; + if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath)) + throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath); + $this->_basePath=$basePath; + } + return $this->_basePath; + } + + /** + * @param string the base path for all themes. It must be in the format of a namespace. + * @throws TInvalidDataValueException if the base path is not a proper namespace. + */ + public function setBasePath($value) + { + if($this->_initialized) + throw new TInvalidOperationException('thememanager_basepath_unchangeable'); + else + { + $this->_basePath=Prado::getPathOfNamespace($value); + if($this->_basePath===null || !is_dir($this->_basePath)) + throw new TInvalidDataValueException('thememanager_basepath_invalid',$value); + } + } + + /** + * @return string the base URL for all themes. + * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado. + */ + public function getBaseUrl() + { + if($this->_baseUrl===null) + { + $appPath=dirname($this->getRequest()->getApplicationFilePath()); + $basePath=$this->getBasePath(); + if(strpos($basePath,$appPath)===false) + throw new TConfigurationException('thememanager_baseurl_required'); + $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\'); + $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/'); + } + return $this->_baseUrl; + } + + /** + * @param string the base URL for all themes. + */ + public function setBaseUrl($value) + { + $this->_baseUrl=rtrim($value,'/'); + } +} + +/** + * TTheme class + * + * TTheme represents a particular theme. It is merely a collection of skins + * that are applicable to the corresponding controls. + * + * Each theme is stored as a directory and files under that directory. + * The theme name is the directory name. When TTheme is created, the files + * whose name has the extension ".skin" are parsed and saved as controls skins. + * + * A skin is essentially a list of initial property values that are to be applied + * to a control when the skin is applied. + * Each type of control can have multiple skins identified by the SkinID. + * If a skin does not have SkinID, it is the default skin that will be applied + * to controls that do not specify particular SkinID. + * + * Whenever possible, TTheme will try to make use of available cache to save + * the parsing time. + * + * To apply a theme to a particular control, call {@link applySkin}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class TTheme extends TApplicationComponent implements ITheme +{ + /** + * prefix for cache variable name used to store parsed themes + */ + const THEME_CACHE_PREFIX='prado:theme:'; + /** + * Extension name of skin files + */ + const SKIN_FILE_EXT='.skin'; + /** + * @var string theme path + */ + private $_themePath; + /** + * @var string theme url + */ + private $_themeUrl; + /** + * @var array list of skins for the theme + */ + private $_skins=null; + /** + * @var string theme name + */ + private $_name=''; + /** + * @var array list of css files + */ + private $_cssFiles=array(); + /** + * @var array list of js files + */ + private $_jsFiles=array(); + + /** + * Constructor. + * @param string theme path + * @param string theme URL + * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files + */ + public function __construct($themePath,$themeUrl) + { + $this->_themeUrl=$themeUrl; + $this->_themePath=realpath($themePath); + $this->_name=basename($themePath); + $cacheValid=false; + // TODO: the following needs to be cleaned up (Qiang) + if(($cache=$this->getApplication()->getCache())!==null) + { + $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath); + if(is_array($array)) + { + list($skins,$cssFiles,$jsFiles,$timestamp)=$array; + if($this->getApplication()->getMode()!==TApplicationMode::Performance) + { + if(($dir=opendir($themePath))===false) + throw new TIOException('theme_path_inexistent',$themePath); + $cacheValid=true; + while(($file=readdir($dir))!==false) + { + if($file==='.' || $file==='..') + continue; + else if(basename($file,'.css')!==$file) + $this->_cssFiles[]=$themeUrl.'/'.$file; + else if(basename($file,'.js')!==$file) + $this->_jsFiles[]=$themeUrl.'/'.$file; + else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp) + { + $cacheValid=false; + break; + } + } + closedir($dir); + if($cacheValid) + $this->_skins=$skins; + } + else + { + $cacheValid=true; + $this->_cssFiles=$cssFiles; + $this->_jsFiles=$jsFiles; + $this->_skins=$skins; + } + } + } + if(!$cacheValid) + { + $this->_cssFiles=array(); + $this->_jsFiles=array(); + $this->_skins=array(); + if(($dir=opendir($themePath))===false) + throw new TIOException('theme_path_inexistent',$themePath); + while(($file=readdir($dir))!==false) + { + if($file==='.' || $file==='..') + continue; + else if(basename($file,'.css')!==$file) + $this->_cssFiles[]=$themeUrl.'/'.$file; + else if(basename($file,'.js')!==$file) + $this->_jsFiles[]=$themeUrl.'/'.$file; + else if(basename($file,self::SKIN_FILE_EXT)!==$file) + { + $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file); + foreach($template->getItems() as $skin) + { + if(!isset($skin[2])) // a text string, ignored + continue; + else if($skin[0]!==-1) + throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath)); + $type=$skin[1]; + $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0; + unset($skin[2]['skinid']); + if(isset($this->_skins[$type][$id])) + throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath)); + /* + foreach($skin[2] as $name=>$value) + { + if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER)) + throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id); + } + */ + $this->_skins[$type][$id]=$skin[2]; + } + } + } + closedir($dir); + sort($this->_cssFiles); + sort($this->_jsFiles); + if($cache!==null) + $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time())); + } + } + + /** + * @return string theme name + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string theme name + */ + protected function setName($value) + { + $this->_name = $value; + } + + /** + * @return string the URL to the theme folder (without ending slash) + */ + public function getBaseUrl() + { + return $this->_themeUrl; + } + + /** + * @param string the URL to the theme folder + */ + protected function setBaseUrl($value) + { + $this->_themeUrl=rtrim($value,'/'); + } + + /** + * @return string the file path to the theme folder + */ + public function getBasePath() + { + return $this->_themePath; + } + + /** + * @param string tthe file path to the theme folder + */ + protected function setBasePath($value) + { + $this->_themePath=$value; + } + + /** + * @return array list of skins for the theme + */ + public function getSkins() + { + return $this->_skins; + } + + /** + * @param array list of skins for the theme + */ + protected function setSkins($value) + { + $this->_skins = $value; + } + + /** + * Applies the theme to a particular control. + * The control's class name and SkinID value will be used to + * identify which skin to be applied. If the control's SkinID is empty, + * the default skin will be applied. + * @param TControl the control to be applied with a skin + * @return boolean if a skin is successfully applied + * @throws TConfigurationException if any error happened during the skin application + */ + public function applySkin($control) + { + $type=get_class($control); + if(($id=$control->getSkinID())==='') + $id=0; + if(isset($this->_skins[$type][$id])) + { + foreach($this->_skins[$type][$id] as $name=>$value) + { + Prado::trace("Applying skin $name to $type",'System.Web.UI.TThemeManager'); + if(is_array($value)) + { + switch($value[0]) + { + case TTemplate::CONFIG_EXPRESSION: + $value=$this->evaluateExpression($value[1]); + break; + case TTemplate::CONFIG_ASSET: + $value=$this->_themeUrl.'/'.ltrim($value[1],'/'); + break; + case TTemplate::CONFIG_DATABIND: + $control->bindProperty($name,$value[1]); + break; + case TTemplate::CONFIG_PARAMETER: + $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); + break; + case TTemplate::CONFIG_TEMPLATE: + $control->setSubProperty($name,$value[1]); + break; + case TTemplate::CONFIG_LOCALIZATION: + $control->setSubProperty($name,Prado::localize($value[1])); + break; + default: + throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]); + break; + } + } + if(!is_array($value)) + { + if(strpos($name,'.')===false) // is simple property or custom attribute + { + if($control->hasProperty($name)) + { + if($control->canSetProperty($name)) + { + $setter='set'.$name; + $control->$setter($value); + } + else + throw new TConfigurationException('theme_property_readonly',$type,$name); + } + else + throw new TConfigurationException('theme_property_undefined',$type,$name); + } + else // complex property + $control->setSubProperty($name,$value); + } + } + return true; + } + else + return false; + } + + /** + * @return array list of CSS files (URL) in the theme + */ + public function getStyleSheetFiles() + { + return $this->_cssFiles; + } + + /** + * @param array list of CSS files (URL) in the theme + */ + protected function setStyleSheetFiles($value) + { + $this->_cssFiles=$value; + } + + /** + * @return array list of Javascript files (URL) in the theme + */ + public function getJavaScriptFiles() + { + return $this->_jsFiles; + } + + /** + * @param array list of Javascript files (URL) in the theme + */ + protected function setJavaScriptFiles($value) + { + $this->_jsFiles=$value; + } +} + +?> diff --git a/framework/Web/UI/WebControls/TAccordion.php b/framework/Web/UI/WebControls/TAccordion.php index 22ff6b71..bfe3451d 100644 --- a/framework/Web/UI/WebControls/TAccordion.php +++ b/framework/Web/UI/WebControls/TAccordion.php @@ -1,744 +1,744 @@ -<?php
-/**
- * TAccordion class file.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-
-/**
- * Class TAccordion.
- *
- * TAccordion displays an accordion control. Users can click on the view headers to switch among
- * different accordion views. Each accordion view is an independent panel that can contain arbitrary content.
- *
- * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible
- * accordion views. At any time, only one accordion view is visible (active), which is specified by any of
- * the following properties:
- * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
- * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
- * - {@link setActiveView ActiveView} - the visible view instance.
- * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
- * are set, the latter takes precedence.
- *
- * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default,
- * an embedded CSS file will be published which contains the default CSS for TTabPanel.
- * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
- * The following properties specify the CSS classes used for elements in a TAccordion:
- * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion');
- * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header');
- * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active');
- * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view');
- *
- * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated.
- * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds;
- * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation.
- *
- * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling.
- * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property.
- * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion
- *
- * To use TAccordion, write a template like following:
- * <code>
- * <com:TAccordion>
- * <com:TAccordionView Caption="View 1">
- * content for view 1
- * </com:TAccordionView>
- * <com:TAccordionView Caption="View 2">
- * content for view 2
- * </com:TAccordionView>
- * <com:TAccordionView Caption="View 3">
- * content for view 3
- * </com:TAccordionView>
- * </com:TAccordion>
- * </code>
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-
-class TAccordion extends TWebControl implements IPostBackDataHandler
-{
- private $_dataChanged=false;
-
- /**
- * @return string tag name for the control
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TAccordionView} objects into the {@link getViews Views} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TAccordionView)
- $this->getControls()->add($object);
- }
-
- /**
- * Returns the index of the active accordion view.
- * Note, this property may not return the correct index.
- * To ensure the correctness, call {@link getActiveView()} first.
- * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active).
- */
- public function getActiveViewIndex()
- {
- return $this->getViewState('ActiveViewIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
- * @throws TInvalidDataValueException if the view index is invalid
- */
- public function setActiveViewIndex($value)
- {
- $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * Returns the ID of the active accordion view.
- * Note, this property may not return the correct ID.
- * To ensure the correctness, call {@link getActiveView()} first.
- * @return string The ID of the active accordion view. Defaults to '', meaning not set.
- */
- public function getActiveViewID()
- {
- return $this->getViewState('ActiveViewID','');
- }
-
- /**
- * @param string The ID of the active accordion view.
- */
- public function setActiveViewID($value)
- {
- $this->setViewState('ActiveViewID',$value,'');
- }
-
- /**
- * Returns the currently active view.
- * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
- * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
- * @return TAccordionView the currently active view, null if no active view
- * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
- */
- public function getActiveView()
- {
- $activeView=null;
- $views=$this->getViews();
- if(($id=$this->getActiveViewID())!=='')
- {
- if(($index=$views->findIndexByID($id))>=0)
- $activeView=$views->itemAt($index);
- else
- throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
- }
- else if(($index=$this->getActiveViewIndex())>=0)
- {
- if($index<$views->getCount())
- $activeView=$views->itemAt($index);
- else
- throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
- }
- else
- {
- foreach($views as $index=>$view)
- {
- if($view->getActive())
- {
- $activeView=$view;
- break;
- }
- }
- }
- if($activeView!==null)
- $this->activateView($activeView);
- return $activeView;
- }
-
- /**
- * @param TAccordionView the view to be activated
- * @throws TInvalidOperationException if the view is not in the view collection
- */
- public function setActiveView($view)
- {
- if($this->getViews()->indexOf($view)>=0)
- $this->activateView($view);
- else
- throw new TInvalidOperationException('tabpanel_view_inexistent');
- }
-
- /**
- * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl','default');
- }
-
- /**
- * @param string URL for the CSS file including all relevant CSS class definitions.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string CSS class for the whole accordion control div.
- */
- public function getCssClass()
- {
- $cssClass=parent::getCssClass();
- return $cssClass===''?'accordion':$cssClass;
- }
-
- /**
- * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
- */
- public function getViewCssClass()
- {
- return $this->getViewStyle()->getCssClass();
- }
-
- /**
- * @param string CSS class for the currently displayed view div.
- */
- public function setViewCssClass($value)
- {
- $this->getViewStyle()->setCssClass($value);
- }
-
- /**
- * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
- */
- public function getAnimationDuration()
- {
- return $this->getViewState('AnimationDuration','1');
- }
-
- /**
- * @param string CSS class for the currently displayed view div.
- */
- public function setAnimationDuration($value)
- {
- $this->setViewState('AnimationDuration',$value);
- }
-
- /**
- * @return TStyle the style for all the view div
- */
- public function getViewStyle()
- {
- if(($style=$this->getViewState('ViewStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-view');
- $this->setViewState('ViewStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string CSS class for view headers. Defaults to 'accordion-header'.
- */
- public function getHeaderCssClass()
- {
- return $this->getHeaderStyle()->getCssClass();
- }
-
- /**
- * @param string CSS class for view headers.
- */
- public function setHeaderCssClass($value)
- {
- $this->getHeaderStyle()->setCssClass($value);
- }
-
- /**
- * @return TStyle the style for all the inactive header div
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-header');
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'.
- */
- public function getActiveHeaderCssClass()
- {
- return $this->getActiveHeaderStyle()->getCssClass();
- }
-
- /**
- * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass.
- */
- public function setActiveHeaderCssClass($value)
- {
- $this->getActiveHeaderStyle()->setCssClass($value);
- }
-
- /**
- * @return TStyle the style for the active header div
- */
- public function getActiveHeaderStyle()
- {
- if(($style=$this->getViewState('ActiveHeaderStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-header-active');
- $this->setViewState('ActiveHeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return integer Maximum height for the accordion views. If non specified, the accordion will auto-sized to the largest of all views, so it can encompass all of them without scrolling
- */
- public function getViewHeight()
- {
- return TPropertyValue::ensureInteger($this->getViewState('ViewHeight'));
- }
-
- /**
- * @param integer Maximum height for the accordion views. If any of the accordion's views' content is larger, those views will be made scrollable when activated
- */
- public function setViewHeight($value)
- {
- $this->setViewState('ViewHeight', TPropertyValue::ensureInteger($value));
- }
-
- /**
- * Activates the specified view.
- * If there is any other view currently active, it will be deactivated.
- * @param TAccordionView the view to be activated. If null, all views will be deactivated.
- */
- protected function activateView($view)
- {
- $this->setActiveViewIndex(-1);
- $this->setActiveViewID('');
- foreach($this->getViews() as $index=>$v)
- {
- if($view===$v)
- {
- $this->setActiveViewIndex($index);
- $this->setActiveViewID($view->getID(false));
- $view->setActive(true);
- }
- else
- $v->setActive(false);
- }
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if(($index=$values[$this->getClientID().'_1'])!==null)
- {
- $index=(int)$index;
- $currentIndex=$this->getActiveViewIndex();
- if($currentIndex!==$index)
- {
- $this->setActiveViewID(''); // clear up view ID
- $this->setActiveViewIndex($index);
- return $this->_dataChanged=true;
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- // do nothing
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->setCssClass($this->getCssClass());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->getActiveView(); // determine the active view
- $this->registerStyleSheet();
- }
-
- /**
- * Registers the CSS relevant to the TAccordion.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- $url = $this->getCssUrl();
-
- if($url === '') {
- return;
- }
-
- if($url === 'default') {
- $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css');
- }
-
- if($url !== '') {
- $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
- }
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $id=$this->getClientID();
- $options=TJavaScript::encode($this->getClientOptions());
- $className=$this->getClientClassName();
- $page=$this->getPage();
- $cs=$page->getClientScript();
- $cs->registerPradoScript('accordion');
- $code="new $className($options);";
- $cs->registerEndScript("prado:$id", $code);
- // ensure an item is always active and visible
- $index = $this->getActiveViewIndex();
- if(!$this->getViews()->itemAt($index)->Visible)
- $index=0;
- $cs->registerHiddenField($id.'_1', $index);
- $page->registerRequiresPostData($this);
- $page->registerRequiresPostData($id."_1");
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TAccordion';
- }
-
- /**
- * @return array the options for JavaScript
- */
- protected function getClientOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['ActiveHeaderCssClass'] = $this->getActiveHeaderCssClass();
- $options['HeaderCssClass'] = $this->getHeaderCssClass();
- $options['Duration'] = $this->getAnimationDuration();
-
- if (($viewheight = $this->getViewHeight())>0)
- $options['maxHeight'] = $viewheight;
- $views = array();
- foreach($this->getViews() as $view)
- $views[$view->getClientID()] = $view->getVisible() ? '1': '0';
- $options['Views'] = $views;
-
- return $options;
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TAccordionViewCollection control collection
- */
- protected function createControlCollection()
- {
- return new TAccordionViewCollection($this);
- }
-
- /**
- * @return TAccordionViewCollection list of {@link TAccordionView} controls
- */
- public function getViews()
- {
- return $this->getControls();
- }
-
- public function render($writer)
- {
- $this->registerClientScript();
- parent::render($writer);
- }
-
- /**
- * Renders body contents of the accordion control.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- $views=$this->getViews();
- if($views->getCount()>0)
- {
- $writer->writeLine();
- foreach($views as $view)
- {
- $view->renderHeader($writer);
- $view->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
-
-}
-
-/**
- * Class TAccordionView.
- *
- * TAccordionView represents a single view in a {@link TAccordion}.
- *
- * TAccordionView is represented inside the {@link TAccordion} with an header label whose text is defined by
- * the {@link setCaption Caption} property; optionally the label can be an hyperlink: use the
- * {@link setNavigateUrl NavigateUrl} property to define the destination url.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TAccordionView extends TWebControl
-{
- private $_active=false;
-
- /**
- * @return the tag name for the view element
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
- $this->getStyle()->setStyleField('display','none');
-
- $this->getStyle()->mergeWith($this->getParent()->getViewStyle());
-
- parent::addAttributesToRender($writer);
-
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * @return string the caption displayed on this header. Defaults to ''.
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string the caption displayed on this header
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL of the target page. Defaults to ''.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL of the target page.
- * If not empty, clicking on this header will redirect the browser to the specified URL.
- * @param string the URL of the target page.
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the text content displayed on this view. Defaults to ''.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content to be displayed on this view.
- * If this is not empty, the child content of the view will be ignored.
- * @param string the text content displayed on this view
- */
- public function setText($value)
- {
- $this->setViewState('Text',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return boolean whether this accordion view is active. Defaults to false.
- */
- public function getActive()
- {
- return $this->_active;
- }
-
- /**
- * @param boolean whether this accordion view is active.
- */
- public function setActive($value)
- {
- $this->_active=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Renders body contents of the accordion view.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())!=='')
- $writer->write($text);
- else if($this->getHasControls())
- parent::renderContents($writer);
- }
-
- /**
- * Renders the header associated with the accordion view.
- * @param THtmlWriter the writer for rendering purpose.
- */
- public function renderHeader($writer)
- {
- if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
- {
- $writer->addAttribute('id',$this->getClientID().'_0');
-
- $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle();
-
- $style->addAttributesToRender($writer);
-
- $writer->renderBeginTag($this->getTagName());
-
- $this->renderHeaderContent($writer);
-
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the content in the header.
- * By default, a hyperlink is displayed.
- * @param THtmlWriter the HTML writer
- */
- protected function renderHeaderContent($writer)
- {
- $url = $this->getNavigateUrl();
- if(($caption=$this->getCaption())==='')
- $caption=' ';
-
- if ($url!='')
- $writer->write("<a href=\"{$url}\">");
- $writer->write("{$caption}");
- if ($url!='')
- $writer->write("</a>");
- }
-}
-
-/**
- * Class TAccordionViewCollection.
- *
- * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TAccordionViewCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing sanity check on the type of new item.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TAccordionView} object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TAccordionView)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
- }
-
- /**
- * Finds the index of the accordion view whose ID is the same as the one being looked for.
- * @param string the explicit ID of the accordion view to be looked for
- * @return integer the index of the accordion view found, -1 if not found.
- */
- public function findIndexByID($id)
- {
- foreach($this as $index=>$view)
- {
- if($view->getID(false)===$id)
- return $index;
- }
- return -1;
- }
-}
-
-?>
+<?php +/** + * TAccordion class file. + * + * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ + +/** + * Class TAccordion. + * + * TAccordion displays an accordion control. Users can click on the view headers to switch among + * different accordion views. Each accordion view is an independent panel that can contain arbitrary content. + * + * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible + * accordion views. At any time, only one accordion view is visible (active), which is specified by any of + * the following properties: + * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection. + * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view. + * - {@link setActiveView ActiveView} - the visible view instance. + * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID} + * are set, the latter takes precedence. + * + * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default, + * an embedded CSS file will be published which contains the default CSS for TTabPanel. + * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property. + * The following properties specify the CSS classes used for elements in a TAccordion: + * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion'); + * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header'); + * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active'); + * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view'); + * + * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated. + * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds; + * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation. + * + * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling. + * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property. + * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion + * + * To use TAccordion, write a template like following: + * <code> + * <com:TAccordion> + * <com:TAccordionView Caption="View 1"> + * content for view 1 + * </com:TAccordionView> + * <com:TAccordionView Caption="View 2"> + * content for view 2 + * </com:TAccordionView> + * <com:TAccordionView Caption="View 3"> + * content for view 3 + * </com:TAccordionView> + * </com:TAccordion> + * </code> + * + * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu> + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ + +class TAccordion extends TWebControl implements IPostBackDataHandler +{ + private $_dataChanged=false; + + /** + * @return string tag name for the control + */ + protected function getTagName() + { + return 'div'; + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TAccordionView} objects into the {@link getViews Views} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + if($object instanceof TAccordionView) + $this->getControls()->add($object); + } + + /** + * Returns the index of the active accordion view. + * Note, this property may not return the correct index. + * To ensure the correctness, call {@link getActiveView()} first. + * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active). + */ + public function getActiveViewIndex() + { + return $this->getViewState('ActiveViewIndex',0); + } + + /** + * @param integer the zero-based index of the current view in the view collection. -1 if no active view. + * @throws TInvalidDataValueException if the view index is invalid + */ + public function setActiveViewIndex($value) + { + $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0); + } + + /** + * Returns the ID of the active accordion view. + * Note, this property may not return the correct ID. + * To ensure the correctness, call {@link getActiveView()} first. + * @return string The ID of the active accordion view. Defaults to '', meaning not set. + */ + public function getActiveViewID() + { + return $this->getViewState('ActiveViewID',''); + } + + /** + * @param string The ID of the active accordion view. + */ + public function setActiveViewID($value) + { + $this->setViewState('ActiveViewID',$value,''); + } + + /** + * Returns the currently active view. + * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to + * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly. + * @return TAccordionView the currently active view, null if no active view + * @throws TInvalidDataValueException if the active view ID or index set previously is invalid + */ + public function getActiveView() + { + $activeView=null; + $views=$this->getViews(); + if(($id=$this->getActiveViewID())!=='') + { + if(($index=$views->findIndexByID($id))>=0) + $activeView=$views->itemAt($index); + else + throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id); + } + else if(($index=$this->getActiveViewIndex())>=0) + { + if($index<$views->getCount()) + $activeView=$views->itemAt($index); + else + throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index); + } + else + { + foreach($views as $index=>$view) + { + if($view->getActive()) + { + $activeView=$view; + break; + } + } + } + if($activeView!==null) + $this->activateView($activeView); + return $activeView; + } + + /** + * @param TAccordionView the view to be activated + * @throws TInvalidOperationException if the view is not in the view collection + */ + public function setActiveView($view) + { + if($this->getViews()->indexOf($view)>=0) + $this->activateView($view); + else + throw new TInvalidOperationException('tabpanel_view_inexistent'); + } + + /** + * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''. + */ + public function getCssUrl() + { + return $this->getViewState('CssUrl','default'); + } + + /** + * @param string URL for the CSS file including all relevant CSS class definitions. + */ + public function setCssUrl($value) + { + $this->setViewState('CssUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return string CSS class for the whole accordion control div. + */ + public function getCssClass() + { + $cssClass=parent::getCssClass(); + return $cssClass===''?'accordion':$cssClass; + } + + /** + * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'. + */ + public function getViewCssClass() + { + return $this->getViewStyle()->getCssClass(); + } + + /** + * @param string CSS class for the currently displayed view div. + */ + public function setViewCssClass($value) + { + $this->getViewStyle()->setCssClass($value); + } + + /** + * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'. + */ + public function getAnimationDuration() + { + return $this->getViewState('AnimationDuration','1'); + } + + /** + * @param string CSS class for the currently displayed view div. + */ + public function setAnimationDuration($value) + { + $this->setViewState('AnimationDuration',$value); + } + + /** + * @return TStyle the style for all the view div + */ + public function getViewStyle() + { + if(($style=$this->getViewState('ViewStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('accordion-view'); + $this->setViewState('ViewStyle',$style,null); + } + return $style; + } + + /** + * @return string CSS class for view headers. Defaults to 'accordion-header'. + */ + public function getHeaderCssClass() + { + return $this->getHeaderStyle()->getCssClass(); + } + + /** + * @param string CSS class for view headers. + */ + public function setHeaderCssClass($value) + { + $this->getHeaderStyle()->setCssClass($value); + } + + /** + * @return TStyle the style for all the inactive header div + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('accordion-header'); + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'. + */ + public function getActiveHeaderCssClass() + { + return $this->getActiveHeaderStyle()->getCssClass(); + } + + /** + * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass. + */ + public function setActiveHeaderCssClass($value) + { + $this->getActiveHeaderStyle()->setCssClass($value); + } + + /** + * @return TStyle the style for the active header div + */ + public function getActiveHeaderStyle() + { + if(($style=$this->getViewState('ActiveHeaderStyle',null))===null) + { + $style=new TStyle; + $style->setCssClass('accordion-header-active'); + $this->setViewState('ActiveHeaderStyle',$style,null); + } + return $style; + } + + /** + * @return integer Maximum height for the accordion views. If non specified, the accordion will auto-sized to the largest of all views, so it can encompass all of them without scrolling + */ + public function getViewHeight() + { + return TPropertyValue::ensureInteger($this->getViewState('ViewHeight')); + } + + /** + * @param integer Maximum height for the accordion views. If any of the accordion's views' content is larger, those views will be made scrollable when activated + */ + public function setViewHeight($value) + { + $this->setViewState('ViewHeight', TPropertyValue::ensureInteger($value)); + } + + /** + * Activates the specified view. + * If there is any other view currently active, it will be deactivated. + * @param TAccordionView the view to be activated. If null, all views will be deactivated. + */ + protected function activateView($view) + { + $this->setActiveViewIndex(-1); + $this->setActiveViewID(''); + foreach($this->getViews() as $index=>$v) + { + if($view===$v) + { + $this->setActiveViewIndex($index); + $this->setActiveViewID($view->getID(false)); + $view->setActive(true); + } + else + $v->setActive(false); + } + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + if(($index=$values[$this->getClientID().'_1'])!==null) + { + $index=(int)$index; + $currentIndex=$this->getActiveViewIndex(); + if($currentIndex!==$index) + { + $this->setActiveViewID(''); // clear up view ID + $this->setActiveViewIndex($index); + return $this->_dataChanged=true; + } + } + return false; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + // do nothing + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $this->setCssClass($this->getCssClass()); + parent::addAttributesToRender($writer); + } + + /** + * Registers CSS and JS. + * This method is invoked right before the control rendering, if the control is visible. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->getActiveView(); // determine the active view + $this->registerStyleSheet(); + } + + /** + * Registers the CSS relevant to the TAccordion. + * It will register the CSS file specified by {@link getCssUrl CssUrl}. + * If that is not set, it will use the default CSS. + */ + protected function registerStyleSheet() + { + $url = $this->getCssUrl(); + + if($url === '') { + return; + } + + if($url === 'default') { + $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css'); + } + + if($url !== '') { + $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url); + } + } + + /** + * Registers the relevant JavaScript. + */ + protected function registerClientScript() + { + $id=$this->getClientID(); + $options=TJavaScript::encode($this->getClientOptions()); + $className=$this->getClientClassName(); + $page=$this->getPage(); + $cs=$page->getClientScript(); + $cs->registerPradoScript('accordion'); + $code="new $className($options);"; + $cs->registerEndScript("prado:$id", $code); + // ensure an item is always active and visible + $index = $this->getActiveViewIndex(); + if(!$this->getViews()->itemAt($index)->Visible) + $index=0; + $cs->registerHiddenField($id.'_1', $index); + $page->registerRequiresPostData($this); + $page->registerRequiresPostData($id."_1"); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TAccordion'; + } + + /** + * @return array the options for JavaScript + */ + protected function getClientOptions() + { + $options['ID'] = $this->getClientID(); + $options['ActiveHeaderCssClass'] = $this->getActiveHeaderCssClass(); + $options['HeaderCssClass'] = $this->getHeaderCssClass(); + $options['Duration'] = $this->getAnimationDuration(); + + if (($viewheight = $this->getViewHeight())>0) + $options['maxHeight'] = $viewheight; + $views = array(); + foreach($this->getViews() as $view) + $views[$view->getClientID()] = $view->getVisible() ? '1': '0'; + $options['Views'] = $views; + + return $options; + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TAccordionViewCollection control collection + */ + protected function createControlCollection() + { + return new TAccordionViewCollection($this); + } + + /** + * @return TAccordionViewCollection list of {@link TAccordionView} controls + */ + public function getViews() + { + return $this->getControls(); + } + + public function render($writer) + { + $this->registerClientScript(); + parent::render($writer); + } + + /** + * Renders body contents of the accordion control. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + $views=$this->getViews(); + if($views->getCount()>0) + { + $writer->writeLine(); + foreach($views as $view) + { + $view->renderHeader($writer); + $view->renderControl($writer); + $writer->writeLine(); + } + } + } + +} + +/** + * Class TAccordionView. + * + * TAccordionView represents a single view in a {@link TAccordion}. + * + * TAccordionView is represented inside the {@link TAccordion} with an header label whose text is defined by + * the {@link setCaption Caption} property; optionally the label can be an hyperlink: use the + * {@link setNavigateUrl NavigateUrl} property to define the destination url. + * + * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu> + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TAccordionView extends TWebControl +{ + private $_active=false; + + /** + * @return the tag name for the view element + */ + protected function getTagName() + { + return 'div'; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript()) + $this->getStyle()->setStyleField('display','none'); + + $this->getStyle()->mergeWith($this->getParent()->getViewStyle()); + + parent::addAttributesToRender($writer); + + $writer->addAttribute('id',$this->getClientID()); + } + + /** + * @return string the caption displayed on this header. Defaults to ''. + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string the caption displayed on this header + */ + public function setCaption($value) + { + $this->setViewState('Caption',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the URL of the target page. Defaults to ''. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL of the target page. + * If not empty, clicking on this header will redirect the browser to the specified URL. + * @param string the URL of the target page. + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the text content displayed on this view. Defaults to ''. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text content to be displayed on this view. + * If this is not empty, the child content of the view will be ignored. + * @param string the text content displayed on this view + */ + public function setText($value) + { + $this->setViewState('Text',TPropertyValue::ensureString($value),''); + } + + /** + * @return boolean whether this accordion view is active. Defaults to false. + */ + public function getActive() + { + return $this->_active; + } + + /** + * @param boolean whether this accordion view is active. + */ + public function setActive($value) + { + $this->_active=TPropertyValue::ensureBoolean($value); + } + + /** + * Renders body contents of the accordion view. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + if(($text=$this->getText())!=='') + $writer->write($text); + else if($this->getHasControls()) + parent::renderContents($writer); + } + + /** + * Renders the header associated with the accordion view. + * @param THtmlWriter the writer for rendering purpose. + */ + public function renderHeader($writer) + { + if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript()) + { + $writer->addAttribute('id',$this->getClientID().'_0'); + + $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle(); + + $style->addAttributesToRender($writer); + + $writer->renderBeginTag($this->getTagName()); + + $this->renderHeaderContent($writer); + + $writer->renderEndTag(); + } + } + + /** + * Renders the content in the header. + * By default, a hyperlink is displayed. + * @param THtmlWriter the HTML writer + */ + protected function renderHeaderContent($writer) + { + $url = $this->getNavigateUrl(); + if(($caption=$this->getCaption())==='') + $caption=' '; + + if ($url!='') + $writer->write("<a href=\"{$url}\">"); + $writer->write("{$caption}"); + if ($url!='') + $writer->write("</a>"); + } +} + +/** + * Class TAccordionViewCollection. + * + * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}. + * + * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu> + * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $ + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TAccordionViewCollection extends TControlCollection +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing sanity check on the type of new item. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TAccordionView} object. + */ + public function insertAt($index,$item) + { + if($item instanceof TAccordionView) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('tabviewcollection_tabview_required'); + } + + /** + * Finds the index of the accordion view whose ID is the same as the one being looked for. + * @param string the explicit ID of the accordion view to be looked for + * @return integer the index of the accordion view found, -1 if not found. + */ + public function findIndexByID($id) + { + foreach($this as $index=>$view) + { + if($view->getID(false)===$id) + return $index; + } + return -1; + } +} + +?> diff --git a/framework/Web/UI/WebControls/TBaseDataList.php b/framework/Web/UI/WebControls/TBaseDataList.php index bc591174..01e7dbcf 100644 --- a/framework/Web/UI/WebControls/TBaseDataList.php +++ b/framework/Web/UI/WebControls/TBaseDataList.php @@ -1,190 +1,190 @@ -<?php
-/**
- * TBaseDataList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TBaseDataList class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TDataBoundControl and TDataFieldAccessor classes
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TBaseDataList class
- *
- * TBaseDataList is the base class for data listing controls, including
- * {@link TDataList} and {@link TDataGrid}.
- *
- * The key field in the data source is specified by {@link setKeyField KeyField},
- * while {@link getKeyValues KeyValues} stores the key values of each record in
- * a data listing control. You may use the list item index to obtain the corresponding
- * database key value.
- *
- * TBaseDataList also implements a few properties used for presentation based
- * on tabular layout. The {@link setCaption Caption}, whose alignment is
- * specified via {@link setCaptionAlign CaptionAlign}, is rendered as the table caption.
- * The table cellpadding and cellspacing are specified by
- * {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
- * properties, respectively. The {@link setGridLines GridLines} specifies how
- * the table should display its borders, and the horizontal alignment of the table
- * content can be specified via {@link setHorizontalAlign HorizontalAlign}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TBaseDataList extends TDataBoundControl
-{
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by the data list control.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return integer the cellspacing for the table layout. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * @param integer the cellspacing for the table layout.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table layout. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * @param integer the cellpadding for the table layout
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return THorizontalAlign::NotSet;
- }
-
- /**
- * @param THorizontalAlign the horizontal alignment of the table content.
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table layout. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getGridLines();
- else
- return TTableGridLines::None;
- }
-
- /**
- * Sets the grid line style of the table layout.
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->getStyle()->setGridLines($value);
- }
-
-
- /**
- * @return string the field of the data source that provides the keys of the list items.
- */
- public function getDataKeyField()
- {
- return $this->getViewState('DataKeyField','');
- }
-
- /**
- * @param string the field of the data source that provides the keys of the list items.
- */
- public function setDataKeyField($value)
- {
- $this->setViewState('DataKeyField',$value,'');
- }
-
- /**
- * @return TList the keys used in the data listing control.
- */
- public function getDataKeys()
- {
- if(($dataKeys=$this->getViewState('DataKeys',null))===null)
- {
- $dataKeys=new TList;
- $this->setViewState('DataKeys',$dataKeys,null);
- }
- return $dataKeys;
- }
-
- /**
- * Returns the value of the data at the specified field.
- * If data is an array, TMap or TList, the value will be returned at the index
- * of the specified field. If the data is a component with a property named
- * as the field name, the property value will be returned.
- * Otherwise, an exception will be raised.
- * @param mixed data item
- * @param mixed field name
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data is invalid
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-
- /**
- * Raises OnSelectedIndexChanged event.
- * This method is invoked when a different item is selected
- * in a data listing control between posts to the server.
- * @param mixed event parameter
- */
- public function onSelectedIndexChanged($param)
- {
- $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TDataBoundControl and TDataFieldAccessor classes + */ +Prado::using('System.Web.UI.WebControls.TDataBoundControl'); +Prado::using('System.Util.TDataFieldAccessor'); + +/** + * TBaseDataList class + * + * TBaseDataList is the base class for data listing controls, including + * {@link TDataList} and {@link TDataGrid}. + * + * The key field in the data source is specified by {@link setKeyField KeyField}, + * while {@link getKeyValues KeyValues} stores the key values of each record in + * a data listing control. You may use the list item index to obtain the corresponding + * database key value. + * + * TBaseDataList also implements a few properties used for presentation based + * on tabular layout. The {@link setCaption Caption}, whose alignment is + * specified via {@link setCaptionAlign CaptionAlign}, is rendered as the table caption. + * The table cellpadding and cellspacing are specified by + * {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing} + * properties, respectively. The {@link setGridLines GridLines} specifies how + * the table should display its borders, and the horizontal alignment of the table + * content can be specified via {@link setHorizontalAlign HorizontalAlign}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TBaseDataList extends TDataBoundControl +{ + /** + * Creates a style object for the control. + * This method creates a {@link TTableStyle} to be used by the data list control. + * @return TTableStyle control style to be used + */ + protected function createStyle() + { + return new TTableStyle; + } + + /** + * @return integer the cellspacing for the table layout. Defaults to -1, meaning not set. + */ + public function getCellSpacing() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellSpacing(); + else + return -1; + } + + /** + * @param integer the cellspacing for the table layout. + */ + public function setCellSpacing($value) + { + $this->getStyle()->setCellSpacing($value); + } + + /** + * @return integer the cellpadding for the table layout. Defaults to -1, meaning not set. + */ + public function getCellPadding() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellPadding(); + else + return -1; + } + + /** + * @param integer the cellpadding for the table layout + */ + public function setCellPadding($value) + { + $this->getStyle()->setCellPadding($value); + } + + /** + * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet. + */ + public function getHorizontalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getHorizontalAlign(); + else + return THorizontalAlign::NotSet; + } + + /** + * @param THorizontalAlign the horizontal alignment of the table content. + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return TTableGridLines the grid line setting of the table layout. Defaults to TTableGridLines::None. + */ + public function getGridLines() + { + if($this->getHasStyle()) + return $this->getStyle()->getGridLines(); + else + return TTableGridLines::None; + } + + /** + * Sets the grid line style of the table layout. + * @param TTableGridLines the grid line setting of the table + */ + public function setGridLines($value) + { + $this->getStyle()->setGridLines($value); + } + + + /** + * @return string the field of the data source that provides the keys of the list items. + */ + public function getDataKeyField() + { + return $this->getViewState('DataKeyField',''); + } + + /** + * @param string the field of the data source that provides the keys of the list items. + */ + public function setDataKeyField($value) + { + $this->setViewState('DataKeyField',$value,''); + } + + /** + * @return TList the keys used in the data listing control. + */ + public function getDataKeys() + { + if(($dataKeys=$this->getViewState('DataKeys',null))===null) + { + $dataKeys=new TList; + $this->setViewState('DataKeys',$dataKeys,null); + } + return $dataKeys; + } + + /** + * Returns the value of the data at the specified field. + * If data is an array, TMap or TList, the value will be returned at the index + * of the specified field. If the data is a component with a property named + * as the field name, the property value will be returned. + * Otherwise, an exception will be raised. + * @param mixed data item + * @param mixed field name + * @return mixed data value at the specified field + * @throws TInvalidDataValueException if the data is invalid + */ + protected function getDataFieldValue($data,$field) + { + return TDataFieldAccessor::getDataFieldValue($data,$field); + } + + /** + * Raises OnSelectedIndexChanged event. + * This method is invoked when a different item is selected + * in a data listing control between posts to the server. + * @param mixed event parameter + */ + public function onSelectedIndexChanged($param) + { + $this->raiseEvent('OnSelectedIndexChanged',$this,$param); + } +} + diff --git a/framework/Web/UI/WebControls/TBoundColumn.php b/framework/Web/UI/WebControls/TBoundColumn.php index 43ef28c2..b7bbc5da 100644 --- a/framework/Web/UI/WebControls/TBoundColumn.php +++ b/framework/Web/UI/WebControls/TBoundColumn.php @@ -1,249 +1,249 @@ -<?php
-/**
- * TBoundColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TBoundColumn class
- *
- * TBoundColumn represents a column that is bound to a field in a data source.
- * The cells in the column will be displayed using the data indexed by
- * {@link setDataField DataField}. You can customize the display by
- * setting {@link setDataFormatString DataFormatString}.
- *
- * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode
- * with textboxes. Otherwise, a static text is displayed.
- *
- * When a datagrid row is in edit mode, the textbox control in the TBoundColumn
- * can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->BoundColumnID->TextBox
- * $datagridItem->BoundColumnID->Controls[0]
- * </code>
- * The second method is possible because the textbox control created within the
- * datagrid cell is the first child.
- *
- * Since v3.1.0, TBoundColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
- * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
- * the layout of the datagrid cells in browsing and editing mode.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBoundColumn extends TDataGridColumn
-{
- /**
- * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the data associated with the datagrid cell during databinding.
- * The data can be either the whole data row or a field of the row if
- * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
- * is not empty, the data will be formatted first before passing to the renderer.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the edit item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the data associated with the datagrid cell during databinding.
- * The data can be either the whole data row or a field of the row if
- * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
- * is not empty, the data will be formatted first before passing to the renderer.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataFormatString()
- {
- return $this->getViewState('DataFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataFormatString($value)
- {
- $this->setViewState('DataFormatString',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a textbox for item in edit mode and the column is not read-only.
- * Otherwise it displays a static text.
- * The caption of the button and the static text are retrieved
- * from the datasource.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- $item=$cell->getParent();
- switch($itemType)
- {
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- if(($classPath=$this->getItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- }
- else
- $control=$cell;
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- case TListItemType::EditItem:
- if(!$this->getReadOnly())
- {
- if(($classPath=$this->getEditItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- $cell->registerObject('EditControl',$control);
- }
- else
- {
- $control=Prado::createComponent('System.Web.UI.WebControls.TTextBox');
- $cell->getControls()->add($control);
- $cell->registerObject('TextBox',$control);
- }
- }
- else
- {
- if(($classPath=$this->getItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- }
- else
- $control=$cell;
- }
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- default:
- parent::initializeCell($cell,$columnIndex,$itemType);
- break;
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- $formatString=$this->getDataFormatString();
- if(($field=$this->getDataField())!=='')
- $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
- else
- $value=$this->formatDataValue($formatString,$data);
- $sender->setData($value);
- }
-}
-
+<?php +/** + * TBoundColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TBoundColumn class + * + * TBoundColumn represents a column that is bound to a field in a data source. + * The cells in the column will be displayed using the data indexed by + * {@link setDataField DataField}. You can customize the display by + * setting {@link setDataFormatString DataFormatString}. + * + * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode + * with textboxes. Otherwise, a static text is displayed. + * + * When a datagrid row is in edit mode, the textbox control in the TBoundColumn + * can be accessed by one of the following two methods: + * <code> + * $datagridItem->BoundColumnID->TextBox + * $datagridItem->BoundColumnID->Controls[0] + * </code> + * The second method is possible because the textbox control created within the + * datagrid cell is the first child. + * + * Since v3.1.0, TBoundColumn has introduced two new properties {@link setItemRenderer ItemRenderer} + * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify + * the layout of the datagrid cells in browsing and editing mode. + * A renderer refers to a control class that is to be instantiated as a control. + * For more details, see {@link TRepeater} and {@link TDataList}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TBoundColumn extends TDataGridColumn +{ + /** + * @return string the class name for the item cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getItemRenderer() + { + return $this->getViewState('ItemRenderer',''); + } + + /** + * Sets the item cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the item cells of the column. + * + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the data associated with the datagrid cell during databinding. + * The data can be either the whole data row or a field of the row if + * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString} + * is not empty, the data will be formatted first before passing to the renderer. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setItemRenderer($value) + { + $this->setViewState('ItemRenderer',$value,''); + } + + /** + * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEditItemRenderer() + { + return $this->getViewState('EditItemRenderer',''); + } + + /** + * Sets the edit item cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode. + * + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the data associated with the datagrid cell during databinding. + * The data can be either the whole data row or a field of the row if + * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString} + * is not empty, the data will be formatted first before passing to the renderer. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setEditItemRenderer($value) + { + $this->setViewState('EditItemRenderer',$value,''); + } + + /** + * @return string the field name from the data source to bind to the column + */ + public function getDataField() + { + return $this->getViewState('DataField',''); + } + + /** + * @param string the field name from the data source to bind to the column + */ + public function setDataField($value) + { + $this->setViewState('DataField',$value,''); + } + + /** + * @return string the formatting string used to control how the bound data will be displayed. + */ + public function getDataFormatString() + { + return $this->getViewState('DataFormatString',''); + } + + /** + * @param string the formatting string used to control how the bound data will be displayed. + */ + public function setDataFormatString($value) + { + $this->setViewState('DataFormatString',$value,''); + } + + /** + * @return boolean whether the items in the column can be edited. Defaults to false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a textbox for item in edit mode and the column is not read-only. + * Otherwise it displays a static text. + * The caption of the button and the static text are retrieved + * from the datasource. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + $item=$cell->getParent(); + switch($itemType) + { + case TListItemType::Item: + case TListItemType::AlternatingItem: + case TListItemType::SelectedItem: + if(($classPath=$this->getItemRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IItemDataRenderer) + { + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $cell->getControls()->add($control); + } + else + $control=$cell; + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + case TListItemType::EditItem: + if(!$this->getReadOnly()) + { + if(($classPath=$this->getEditItemRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IItemDataRenderer) + { + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $cell->getControls()->add($control); + $cell->registerObject('EditControl',$control); + } + else + { + $control=Prado::createComponent('System.Web.UI.WebControls.TTextBox'); + $cell->getControls()->add($control); + $cell->registerObject('TextBox',$control); + } + } + else + { + if(($classPath=$this->getItemRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IItemDataRenderer) + { + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $cell->getControls()->add($control); + } + else + $control=$cell; + } + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + default: + parent::initializeCell($cell,$columnIndex,$itemType); + break; + } + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + $formatString=$this->getDataFormatString(); + if(($field=$this->getDataField())!=='') + $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field)); + else + $value=$this->formatDataValue($formatString,$data); + $sender->setData($value); + } +} + diff --git a/framework/Web/UI/WebControls/TBulletedList.php b/framework/Web/UI/WebControls/TBulletedList.php index 1b32059f..51982c3e 100644 --- a/framework/Web/UI/WebControls/TBulletedList.php +++ b/framework/Web/UI/WebControls/TBulletedList.php @@ -1,492 +1,492 @@ -<?php
-/**
- * TBulletedList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TBulletedList class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TBulletedList class
- *
- * TBulletedList displays items in a bullet format.
- * The bullet style is specified by {@link setBulletStyle BulletStyle}. When
- * the style is 'CustomImage', the {@link setBackImageUrl BulletImageUrl}
- * specifies the image used as bullets.
- *
- * TBulletedList displays the item texts in three different modes, specified
- * via {@link setDisplayMode DisplayMode}. When the mode is Text, the item texts
- * are displayed as static texts; When the mode is 'HyperLink', each item
- * is displayed as a hyperlink whose URL is given by the item value, and the
- * {@link setTarget Target} property can be used to specify the target browser window;
- * When the mode is 'LinkButton', each item is displayed as a link button which
- * posts back to the page if a user clicks on that and the event {@link onClick OnClick}
- * will be raised under such a circumstance.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBulletedList extends TListControl implements IPostBackEventHandler
-{
- /**
- * @var boolean cached property value of Enabled
- */
- private $_isEnabled;
- /**
- * @var TPostBackOptions postback options
- */
- private $_postBackOptions;
-
- private $_currentRenderItemIndex;
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(new TBulletedListEventParameter((int)$param));
- }
-
- /**
- * @return string tag name of the bulleted list
- */
- protected function getTagName()
- {
- switch($this->getBulletStyle())
- {
- case TBulletStyle::Numbered:
- case TBulletStyle::LowerAlpha:
- case TBulletStyle::UpperAlpha:
- case TBulletStyle::LowerRoman:
- case TBulletStyle::UpperRoman:
- return 'ol';
- }
- return 'ul';
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TBulletedList';
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional bulleted list specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $needStart=false;
- switch($this->getBulletStyle())
- {
- case TBulletStyle::None:
- $writer->addStyleAttribute('list-style-type','none');
- $needStart=true;
- break;
- case TBulletStyle::Numbered:
- $writer->addStyleAttribute('list-style-type','decimal');
- $needStart=true;
- break;
- case TBulletStyle::LowerAlpha:
- $writer->addStyleAttribute('list-style-type','lower-alpha');
- $needStart=true;
- break;
- case TBulletStyle::UpperAlpha:
- $writer->addStyleAttribute('list-style-type','upper-alpha');
- $needStart=true;
- break;
- case TBulletStyle::LowerRoman:
- $writer->addStyleAttribute('list-style-type','lower-roman');
- $needStart=true;
- break;
- case TBulletStyle::UpperRoman:
- $writer->addStyleAttribute('list-style-type','upper-roman');
- $needStart=true;
- break;
- case TBulletStyle::Disc:
- $writer->addStyleAttribute('list-style-type','disc');
- break;
- case TBulletStyle::Circle:
- $writer->addStyleAttribute('list-style-type','circle');
- break;
- case TBulletStyle::Square:
- $writer->addStyleAttribute('list-style-type','square');
- break;
- case TBulletStyle::CustomImage:
- $url=$this->getBulletImageUrl();
- $writer->addStyleAttribute('list-style-image',"url($url)");
- break;
- }
- if($needStart && ($start=$this->getFirstBulletNumber())!=1)
- $writer->addAttribute('start',"$start");
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
- */
- public function getBulletImageUrl()
- {
- return $this->getViewState('BulletImageUrl','');
- }
-
- /**
- * @param string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
- */
- public function setBulletImageUrl($value)
- {
- $this->setViewState('BulletImageUrl',$value,'');
- }
-
- /**
- * @return TBulletStyle style of bullets. Defaults to TBulletStyle::NotSet.
- */
- public function getBulletStyle()
- {
- return $this->getViewState('BulletStyle',TBulletStyle::NotSet);
- }
-
- /**
- * @param TBulletStyle style of bullets.
- */
- public function setBulletStyle($value)
- {
- $this->setViewState('BulletStyle',TPropertyValue::ensureEnum($value,'TBulletStyle'),TBulletStyle::NotSet);
- }
-
- /**
- * @return TBulletedListDisplayMode display mode of the list. Defaults to TBulletedListDisplayMode::Text.
- */
- public function getDisplayMode()
- {
- return $this->getViewState('DisplayMode',TBulletedListDisplayMode::Text);
- }
-
- /**
- * @return TBulletedListDisplayMode display mode of the list.
- */
- public function setDisplayMode($value)
- {
- $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TBulletedListDisplayMode'),TBulletedListDisplayMode::Text);
- }
-
- /**
- * @return integer starting index when {@link getBulletStyle BulletStyle} is one of
- * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
- * Defaults to 1.
- */
- public function getFirstBulletNumber()
- {
- return $this->getViewState('FirstBulletNumber',1);
- }
-
- /**
- * @param integer starting index when {@link getBulletStyle BulletStyle} is one of
- * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
- */
- public function setFirstBulletNumber($value)
- {
- $this->setViewState('FirstBulletNumber',TPropertyValue::ensureInteger($value),1);
- }
-
- /**
- * Raises 'OnClick' event.
- * This method is invoked when the {@link getDisplayMode DisplayMode} is 'LinkButton'
- * and end-users click on one of the buttons.
- * @param TBulletedListEventParameter event parameter.
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * @return string the target window or frame to display the Web page content
- * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
- * the hyperlinks is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the Web page content
- * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
- * the hyperlinks is clicked.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-
- /**
- * Renders the control.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function render($writer)
- {
- if($this->getHasItems())
- parent::render($writer);
- }
-
- /**
- * Renders the body contents.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function renderContents($writer)
- {
- $this->_isEnabled=$this->getEnabled(true);
- $this->_postBackOptions=$this->getPostBackOptions();
- $writer->writeLine();
- foreach($this->getItems() as $index=>$item)
- {
- if($item->getHasAttributes())
- $writer->addAttributes($item->getAttributes());
- $writer->renderBeginTag('li');
- $this->renderBulletText($writer,$item,$index);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
-
- /**
- * Renders each item
- * @param THtmlWriter writer for the rendering purpose
- * @param TListItem item to be rendered
- * @param integer index of the item being rendered
- */
- protected function renderBulletText($writer,$item,$index)
- {
- switch($this->getDisplayMode())
- {
- case TBulletedListDisplayMode::Text:
- $this->renderTextItem($writer, $item, $index);
- break;
- case TBulletedListDisplayMode::HyperLink:
- $this->renderHyperLinkItem($writer, $item, $index);
- break;
- case TBulletedListDisplayMode::LinkButton:
- $this->renderLinkButtonItem($writer, $item, $index);
- break;
- }
- }
-
- protected function renderTextItem($writer, $item, $index)
- {
- if($item->getEnabled())
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- else
- {
- $writer->addAttribute('disabled','disabled');
- $writer->renderBeginTag('span');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
- }
-
- protected function renderHyperLinkItem($writer, $item, $index)
- {
- if(!$this->_isEnabled || !$item->getEnabled())
- $writer->addAttribute('disabled','disabled');
- else
- {
- $writer->addAttribute('href',$item->getValue());
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- $writer->renderBeginTag('a');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
-
- protected function renderLinkButtonItem($writer, $item, $index)
- {
- if(!$this->_isEnabled || !$item->getEnabled())
- $writer->addAttribute('disabled','disabled');
- else
- {
- $this->_currentRenderItemIndex = $index;
- $writer->addAttribute('id', $this->getClientID().$index);
- $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index);
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- $writer->renderBeginTag('a');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
-
- /**
- * @return array postback options used for linkbuttons.
- */
- protected function getPostBackOptions()
- {
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- $options['EventParameter'] = $this->_currentRenderItemIndex;
- $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex;
- $options['StopEvent'] = true;
- return $options;
- }
-
- protected function canCauseValidation()
- {
- $group = $this->getValidationGroup();
- $hasValidators = $this->getPage()->getValidators($group)->getCount()>0;
- return $this->getCausesValidation() && $hasValidators;
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setAutoPostBack($value)
- {
- throw new TNotSupportedException('bulletedlist_autopostback_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndex($index)
- {
- throw new TNotSupportedException('bulletedlist_selectedindex_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndices($indices)
- {
- throw new TNotSupportedException('bulletedlist_selectedindices_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedValue($value)
- {
- throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedValues($values)
- {
- throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
- }
-}
-
-/**
- * TBulletedListEventParameter
- * Event parameter for {@link TBulletedList::onClick Click} event of the
- * bulleted list. The {@link getIndex Index} gives the zero-based index
- * of the item that is currently being clicked.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBulletedListEventParameter extends TEventParameter
-{
- /**
- * @var integer index of the item clicked
- */
- private $_index;
-
- /**
- * Constructor.
- * @param integer index of the item clicked
- */
- public function __construct($index)
- {
- $this->_index=$index;
- }
-
- /**
- * @return integer zero-based index of the item (rendered as a link button) that is clicked
- */
- public function getIndex()
- {
- return $this->_index;
- }
-}
-
-/**
- * TBulletStyle class.
- * TBulletStyle defines the enumerable type for the possible bullet styles that may be used
- * for a {@link TBulletedList} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TBulletStyle extends TEnumerable
-{
- const NotSet='NotSet';
- const None='None';
- const Numbered='Numbered';
- const LowerAlpha='LowerAlpha';
- const UpperAlpha='UpperAlpha';
- const LowerRoman='LowerRoman';
- const UpperRoman='UpperRoman';
- const Disc='Disc';
- const Circle='Circle';
- const Square='Square';
- const CustomImage='CustomImage';
-}
-
-/**
- * TBulletedListDisplayMode class.
- * TBulletedListDisplayMode defines the enumerable type for the possible display mode
- * of a {@link TBulletedList} control.
- *
- * The following enumerable values are defined:
- * - Text: the bulleted list items are displayed as plain texts
- * - HyperLink: the bulleted list items are displayed as hyperlinks
- * - LinkButton: the bulleted list items are displayed as link buttons that can cause postbacks
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TBulletedListDisplayMode extends TEnumerable
-{
- const Text='Text';
- const HyperLink='HyperLink';
- const LinkButton='LinkButton';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * TBulletedList class + * + * TBulletedList displays items in a bullet format. + * The bullet style is specified by {@link setBulletStyle BulletStyle}. When + * the style is 'CustomImage', the {@link setBackImageUrl BulletImageUrl} + * specifies the image used as bullets. + * + * TBulletedList displays the item texts in three different modes, specified + * via {@link setDisplayMode DisplayMode}. When the mode is Text, the item texts + * are displayed as static texts; When the mode is 'HyperLink', each item + * is displayed as a hyperlink whose URL is given by the item value, and the + * {@link setTarget Target} property can be used to specify the target browser window; + * When the mode is 'LinkButton', each item is displayed as a link button which + * posts back to the page if a user clicks on that and the event {@link onClick OnClick} + * will be raised under such a circumstance. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TBulletedList extends TListControl implements IPostBackEventHandler +{ + /** + * @var boolean cached property value of Enabled + */ + private $_isEnabled; + /** + * @var TPostBackOptions postback options + */ + private $_postBackOptions; + + private $_currentRenderItemIndex; + + /** + * Raises the postback event. + * This method is required by {@link IPostBackEventHandler} interface. + * If {@link getCausesValidation CausesValidation} is true, it will + * invoke the page's {@link TPage::validate validate} method first. + * It will raise {@link onClick OnClick} events. + * This method is mainly used by framework and control developers. + * @param TEventParameter the event parameter + */ + public function raisePostBackEvent($param) + { + if($this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onClick(new TBulletedListEventParameter((int)$param)); + } + + /** + * @return string tag name of the bulleted list + */ + protected function getTagName() + { + switch($this->getBulletStyle()) + { + case TBulletStyle::Numbered: + case TBulletStyle::LowerAlpha: + case TBulletStyle::UpperAlpha: + case TBulletStyle::LowerRoman: + case TBulletStyle::UpperRoman: + return 'ol'; + } + return 'ul'; + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TBulletedList'; + } + + /** + * Adds attribute name-value pairs to renderer. + * This overrides the parent implementation with additional bulleted list specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $needStart=false; + switch($this->getBulletStyle()) + { + case TBulletStyle::None: + $writer->addStyleAttribute('list-style-type','none'); + $needStart=true; + break; + case TBulletStyle::Numbered: + $writer->addStyleAttribute('list-style-type','decimal'); + $needStart=true; + break; + case TBulletStyle::LowerAlpha: + $writer->addStyleAttribute('list-style-type','lower-alpha'); + $needStart=true; + break; + case TBulletStyle::UpperAlpha: + $writer->addStyleAttribute('list-style-type','upper-alpha'); + $needStart=true; + break; + case TBulletStyle::LowerRoman: + $writer->addStyleAttribute('list-style-type','lower-roman'); + $needStart=true; + break; + case TBulletStyle::UpperRoman: + $writer->addStyleAttribute('list-style-type','upper-roman'); + $needStart=true; + break; + case TBulletStyle::Disc: + $writer->addStyleAttribute('list-style-type','disc'); + break; + case TBulletStyle::Circle: + $writer->addStyleAttribute('list-style-type','circle'); + break; + case TBulletStyle::Square: + $writer->addStyleAttribute('list-style-type','square'); + break; + case TBulletStyle::CustomImage: + $url=$this->getBulletImageUrl(); + $writer->addStyleAttribute('list-style-image',"url($url)"); + break; + } + if($needStart && ($start=$this->getFirstBulletNumber())!=1) + $writer->addAttribute('start',"$start"); + parent::addAttributesToRender($writer); + } + + /** + * @return string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'. + */ + public function getBulletImageUrl() + { + return $this->getViewState('BulletImageUrl',''); + } + + /** + * @param string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'. + */ + public function setBulletImageUrl($value) + { + $this->setViewState('BulletImageUrl',$value,''); + } + + /** + * @return TBulletStyle style of bullets. Defaults to TBulletStyle::NotSet. + */ + public function getBulletStyle() + { + return $this->getViewState('BulletStyle',TBulletStyle::NotSet); + } + + /** + * @param TBulletStyle style of bullets. + */ + public function setBulletStyle($value) + { + $this->setViewState('BulletStyle',TPropertyValue::ensureEnum($value,'TBulletStyle'),TBulletStyle::NotSet); + } + + /** + * @return TBulletedListDisplayMode display mode of the list. Defaults to TBulletedListDisplayMode::Text. + */ + public function getDisplayMode() + { + return $this->getViewState('DisplayMode',TBulletedListDisplayMode::Text); + } + + /** + * @return TBulletedListDisplayMode display mode of the list. + */ + public function setDisplayMode($value) + { + $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TBulletedListDisplayMode'),TBulletedListDisplayMode::Text); + } + + /** + * @return integer starting index when {@link getBulletStyle BulletStyle} is one of + * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'. + * Defaults to 1. + */ + public function getFirstBulletNumber() + { + return $this->getViewState('FirstBulletNumber',1); + } + + /** + * @param integer starting index when {@link getBulletStyle BulletStyle} is one of + * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'. + */ + public function setFirstBulletNumber($value) + { + $this->setViewState('FirstBulletNumber',TPropertyValue::ensureInteger($value),1); + } + + /** + * Raises 'OnClick' event. + * This method is invoked when the {@link getDisplayMode DisplayMode} is 'LinkButton' + * and end-users click on one of the buttons. + * @param TBulletedListEventParameter event parameter. + */ + public function onClick($param) + { + $this->raiseEvent('OnClick',$this,$param); + } + + /** + * @return string the target window or frame to display the Web page content + * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of + * the hyperlinks is clicked. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * @param string the target window or frame to display the Web page content + * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of + * the hyperlinks is clicked. + */ + public function setTarget($value) + { + $this->setViewState('Target',$value,''); + } + + /** + * Renders the control. + * @param THtmlWriter the writer for the rendering purpose. + */ + public function render($writer) + { + if($this->getHasItems()) + parent::render($writer); + } + + /** + * Renders the body contents. + * @param THtmlWriter the writer for the rendering purpose. + */ + public function renderContents($writer) + { + $this->_isEnabled=$this->getEnabled(true); + $this->_postBackOptions=$this->getPostBackOptions(); + $writer->writeLine(); + foreach($this->getItems() as $index=>$item) + { + if($item->getHasAttributes()) + $writer->addAttributes($item->getAttributes()); + $writer->renderBeginTag('li'); + $this->renderBulletText($writer,$item,$index); + $writer->renderEndTag(); + $writer->writeLine(); + } + } + + /** + * Renders each item + * @param THtmlWriter writer for the rendering purpose + * @param TListItem item to be rendered + * @param integer index of the item being rendered + */ + protected function renderBulletText($writer,$item,$index) + { + switch($this->getDisplayMode()) + { + case TBulletedListDisplayMode::Text: + $this->renderTextItem($writer, $item, $index); + break; + case TBulletedListDisplayMode::HyperLink: + $this->renderHyperLinkItem($writer, $item, $index); + break; + case TBulletedListDisplayMode::LinkButton: + $this->renderLinkButtonItem($writer, $item, $index); + break; + } + } + + protected function renderTextItem($writer, $item, $index) + { + if($item->getEnabled()) + $writer->write(THttpUtility::htmlEncode($item->getText())); + else + { + $writer->addAttribute('disabled','disabled'); + $writer->renderBeginTag('span'); + $writer->write(THttpUtility::htmlEncode($item->getText())); + $writer->renderEndTag(); + } + } + + protected function renderHyperLinkItem($writer, $item, $index) + { + if(!$this->_isEnabled || !$item->getEnabled()) + $writer->addAttribute('disabled','disabled'); + else + { + $writer->addAttribute('href',$item->getValue()); + if(($target=$this->getTarget())!=='') + $writer->addAttribute('target',$target); + } + if(($accesskey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accesskey); + $writer->renderBeginTag('a'); + $writer->write(THttpUtility::htmlEncode($item->getText())); + $writer->renderEndTag(); + } + + protected function renderLinkButtonItem($writer, $item, $index) + { + if(!$this->_isEnabled || !$item->getEnabled()) + $writer->addAttribute('disabled','disabled'); + else + { + $this->_currentRenderItemIndex = $index; + $writer->addAttribute('id', $this->getClientID().$index); + $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index); + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + if(($accesskey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accesskey); + $writer->renderBeginTag('a'); + $writer->write(THttpUtility::htmlEncode($item->getText())); + $writer->renderEndTag(); + } + + /** + * @return array postback options used for linkbuttons. + */ + protected function getPostBackOptions() + { + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['EventTarget'] = $this->getUniqueID(); + $options['EventParameter'] = $this->_currentRenderItemIndex; + $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex; + $options['StopEvent'] = true; + return $options; + } + + protected function canCauseValidation() + { + $group = $this->getValidationGroup(); + $hasValidators = $this->getPage()->getValidators($group)->getCount()>0; + return $this->getCausesValidation() && $hasValidators; + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setAutoPostBack($value) + { + throw new TNotSupportedException('bulletedlist_autopostback_unsupported'); + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedIndex($index) + { + throw new TNotSupportedException('bulletedlist_selectedindex_unsupported'); + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedIndices($indices) + { + throw new TNotSupportedException('bulletedlist_selectedindices_unsupported'); + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedValue($value) + { + throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported'); + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedValues($values) + { + throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported'); + } +} + +/** + * TBulletedListEventParameter + * Event parameter for {@link TBulletedList::onClick Click} event of the + * bulleted list. The {@link getIndex Index} gives the zero-based index + * of the item that is currently being clicked. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TBulletedListEventParameter extends TEventParameter +{ + /** + * @var integer index of the item clicked + */ + private $_index; + + /** + * Constructor. + * @param integer index of the item clicked + */ + public function __construct($index) + { + $this->_index=$index; + } + + /** + * @return integer zero-based index of the item (rendered as a link button) that is clicked + */ + public function getIndex() + { + return $this->_index; + } +} + +/** + * TBulletStyle class. + * TBulletStyle defines the enumerable type for the possible bullet styles that may be used + * for a {@link TBulletedList} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TBulletStyle extends TEnumerable +{ + const NotSet='NotSet'; + const None='None'; + const Numbered='Numbered'; + const LowerAlpha='LowerAlpha'; + const UpperAlpha='UpperAlpha'; + const LowerRoman='LowerRoman'; + const UpperRoman='UpperRoman'; + const Disc='Disc'; + const Circle='Circle'; + const Square='Square'; + const CustomImage='CustomImage'; +} + +/** + * TBulletedListDisplayMode class. + * TBulletedListDisplayMode defines the enumerable type for the possible display mode + * of a {@link TBulletedList} control. + * + * The following enumerable values are defined: + * - Text: the bulleted list items are displayed as plain texts + * - HyperLink: the bulleted list items are displayed as hyperlinks + * - LinkButton: the bulleted list items are displayed as link buttons that can cause postbacks + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TBulletedListDisplayMode extends TEnumerable +{ + const Text='Text'; + const HyperLink='HyperLink'; + const LinkButton='LinkButton'; +} + diff --git a/framework/Web/UI/WebControls/TButton.php b/framework/Web/UI/WebControls/TButton.php index 71256a5b..caa0332c 100644 --- a/framework/Web/UI/WebControls/TButton.php +++ b/framework/Web/UI/WebControls/TButton.php @@ -1,368 +1,368 @@ -<?php
-/**
- * TButton class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TButton class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TButton class
- *
- * TButton creates a click button on the page. It is mainly used to submit data to a page.
- *
- * TButton raises two server-side events, {@link onClick OnClick} and {@link onCommand OnCommand},
- * when it is clicked on the client-side. The difference between these two events
- * is that the event {@link onCommand OnCommand} is bubbled up to the button's ancestor controls.
- * And within the event parameter for {@link onCommand OnCommand} contains the reference
- * to the {@link setCommandName CommandName} and {@link setCommandParameter CommandParameter}
- * property values that are set for the button object. This allows you to create multiple TButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter.
- *
- * Clicking on button can also trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * The validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TButton displays the {@link setText Text} property as the button caption.
- *
- * TButton can be one of three {@link setButtonType ButtonType}: Submit, Button and Reset.
- * By default, it is a Submit button and the form submission uses the browser's
- * default submission capability. If it is Button or Reset, postback may occur
- * if one of the following conditions is met:
- * - an event handler is attached to {@link onClick OnClick} event;
- * - an event handler is attached to {@link onCommand OnCommand} event;
- * - the button is in a non-empty validation group.
- * In addition, clicking on a Reset button will clear up all input fields
- * if the button does not cause a postback.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
-{
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- $writer->addAttribute('type',strtolower($this->getButtonType()));
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- $writer->addAttribute('value',$this->getText());
- if($this->getEnabled(true))
- {
- if($this->getEnableClientScript() && $this->needPostBackScript())
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TButton';
- }
-
- /**
- * @return boolean whether to perform validation if the button is clicked
- */
- protected function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * @return boolean whether the button needs javascript to do postback
- */
- protected function needPostBackScript()
- {
- return $this->canCauseValidation() || ($this->getButtonType()!==TButtonType::Submit &&
- ($this->hasEventHandler('OnClick') || $this->hasEventHandler('OnCommand')))
- || $this->getIsDefaultButton();
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID']=$this->getClientID();
- $options['CausesValidation']=$this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- $options['ValidationGroup']=$this->getValidationGroup();
-
- return $options;
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * This overrides the parent implementation with nothing to be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(null);
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * @return string caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string caption of the button
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string caption of the button.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string caption of the button
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return TButtonType the type of the button. Defaults to TButtonType::Submit.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonType::Submit);
- }
-
- /**
- * @param TButtonType the type of the button.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonType'),TButtonType::Submit);
- }
-}
-
-/**
- * TButtonType class.
- * TButtonType defines the enumerable type for the possible types that a {@link TButton} can take.
- *
- * The following enumerable values are defined:
- * - Submit: a normal submit button
- * - Reset: a reset button
- * - Button: a client button (normally does not perform form submission)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TButtonType extends TEnumerable
-{
- const Submit='Submit';
- const Reset='Reset';
- const Button='Button';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TButton class + * + * TButton creates a click button on the page. It is mainly used to submit data to a page. + * + * TButton raises two server-side events, {@link onClick OnClick} and {@link onCommand OnCommand}, + * when it is clicked on the client-side. The difference between these two events + * is that the event {@link onCommand OnCommand} is bubbled up to the button's ancestor controls. + * And within the event parameter for {@link onCommand OnCommand} contains the reference + * to the {@link setCommandName CommandName} and {@link setCommandParameter CommandParameter} + * property values that are set for the button object. This allows you to create multiple TButton + * components on a Web page and programmatically determine which one is clicked + * with what parameter. + * + * Clicking on button can also trigger form validation, if + * {@link setCausesValidation CausesValidation} is true. + * The validation may be restricted within a certain group of validator + * controls by setting {@link setValidationGroup ValidationGroup} property. + * If validation is successful, the data will be post back to the same page. + * + * TButton displays the {@link setText Text} property as the button caption. + * + * TButton can be one of three {@link setButtonType ButtonType}: Submit, Button and Reset. + * By default, it is a Submit button and the form submission uses the browser's + * default submission capability. If it is Button or Reset, postback may occur + * if one of the following conditions is met: + * - an event handler is attached to {@link onClick OnClick} event; + * - an event handler is attached to {@link onCommand OnCommand} event; + * - the button is in a non-empty validation group. + * In addition, clicking on a Reset button will clear up all input fields + * if the button does not cause a postback. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer +{ + /** + * @return string tag name of the button + */ + protected function getTagName() + { + return 'input'; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Adds attribute name-value pairs to renderer. + * This overrides the parent implementation with additional button specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $page=$this->getPage(); + $page->ensureRenderInForm($this); + $writer->addAttribute('type',strtolower($this->getButtonType())); + if(($uniqueID=$this->getUniqueID())!=='') + $writer->addAttribute('name',$uniqueID); + $writer->addAttribute('value',$this->getText()); + if($this->getEnabled(true)) + { + if($this->getEnableClientScript() && $this->needPostBackScript()) + $this->renderClientControlScript($writer); + } + else if($this->getEnabled()) // in this case, parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + + parent::addAttributesToRender($writer); + } + + /** + * Renders the client-script code. + */ + protected function renderClientControlScript($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TButton'; + } + + /** + * @return boolean whether to perform validation if the button is clicked + */ + protected function canCauseValidation() + { + if($this->getCausesValidation()) + { + $group=$this->getValidationGroup(); + return $this->getPage()->getValidators($group)->getCount()>0; + } + else + return false; + } + + /** + * @param boolean set by a panel to register this button as the default button for the panel. + */ + public function setIsDefaultButton($value) + { + $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean true if this button is registered as a default button for a panel. + */ + public function getIsDefaultButton() + { + return $this->getViewState('IsDefaultButton', false); + } + + /** + * @return boolean whether the button needs javascript to do postback + */ + protected function needPostBackScript() + { + return $this->canCauseValidation() || ($this->getButtonType()!==TButtonType::Submit && + ($this->hasEventHandler('OnClick') || $this->hasEventHandler('OnCommand'))) + || $this->getIsDefaultButton(); + } + + /** + * Returns postback specifications for the button. + * This method is used by framework and control developers. + * @return array parameters about how the button defines its postback behavior. + */ + protected function getPostBackOptions() + { + $options['ID']=$this->getClientID(); + $options['CausesValidation']=$this->getCausesValidation(); + $options['EventTarget'] = $this->getUniqueID(); + $options['ValidationGroup']=$this->getValidationGroup(); + + return $options; + } + + /** + * Renders the body content enclosed between the control tag. + * This overrides the parent implementation with nothing to be rendered. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnClick' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handler can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param) + { + $this->raiseEvent('OnClick',$this,$param); + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnCommand' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TCommandEventParameter event parameter to be passed to the event handlers + */ + public function onCommand($param) + { + $this->raiseEvent('OnCommand',$this,$param); + $this->raiseBubbleEvent($this,$param); + } + + /** + * Raises the postback event. + * This method is required by {@link IPostBackEventHandler} interface. + * If {@link getCausesValidation CausesValidation} is true, it will + * invoke the page's {@link TPage::validate validate} method first. + * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events. + * This method is mainly used by framework and control developers. + * @param TEventParameter the event parameter + */ + public function raisePostBackEvent($param) + { + if($this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onClick(null); + $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter())); + } + + /** + * @return string caption of the button + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * @param string caption of the button + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the caption of the button. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string caption of the button. + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the caption of the button. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string caption of the button + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return boolean whether postback event trigger by this button will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this button will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the command name associated with the {@link onCommand OnCommand} event. + */ + public function getCommandName() + { + return $this->getViewState('CommandName',''); + } + + /** + * @param string the command name associated with the {@link onCommand OnCommand} event. + */ + public function setCommandName($value) + { + $this->setViewState('CommandName',$value,''); + } + + /** + * @return string the parameter associated with the {@link onCommand OnCommand} event + */ + public function getCommandParameter() + { + return $this->getViewState('CommandParameter',''); + } + + /** + * @param string the parameter associated with the {@link onCommand OnCommand} event. + */ + public function setCommandParameter($value) + { + $this->setViewState('CommandParameter',$value,''); + } + + /** + * @return string the group of validators which the button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return TButtonType the type of the button. Defaults to TButtonType::Submit. + */ + public function getButtonType() + { + return $this->getViewState('ButtonType',TButtonType::Submit); + } + + /** + * @param TButtonType the type of the button. + */ + public function setButtonType($value) + { + $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonType'),TButtonType::Submit); + } +} + +/** + * TButtonType class. + * TButtonType defines the enumerable type for the possible types that a {@link TButton} can take. + * + * The following enumerable values are defined: + * - Submit: a normal submit button + * - Reset: a reset button + * - Button: a client button (normally does not perform form submission) + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TButtonType extends TEnumerable +{ + const Submit='Submit'; + const Reset='Reset'; + const Button='Button'; +} + diff --git a/framework/Web/UI/WebControls/TButtonColumn.php b/framework/Web/UI/WebControls/TButtonColumn.php index 9d754004..f0f387e7 100644 --- a/framework/Web/UI/WebControls/TButtonColumn.php +++ b/framework/Web/UI/WebControls/TButtonColumn.php @@ -1,278 +1,278 @@ -<?php
-/**
- * TButtonColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TButtonColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-Prado::using('System.Web.UI.WebControls.TButton');
-Prado::using('System.Web.UI.WebControls.TLinkButton');
-Prado::using('System.Web.UI.WebControls.TImageButton');
-
-/**
- * TButtonColumn class
- *
- * TButtonColumn contains a user-defined command button, such as Add or Remove,
- * that corresponds with each row in the column.
- *
- * The caption of the buttons in the column is determined by {@link setText Text}
- * and {@link setDataTextField DataTextField} properties. If both are present,
- * the latter takes precedence. The {@link setDataTextField DataTextField} property
- * refers to the name of the field in datasource whose value will be used as the button caption.
- * If {@link setDataTextFormatString DataTextFormatString} is not empty,
- * the value will be formatted before rendering.
- *
- * The buttons in the column can be set to display as hyperlinks or push buttons
- * by setting the {@link setButtonType ButtonType} property.
- * The {@link setCommandName CommandName} will assign its value to
- * all button's <b>CommandName</b> property. The datagrid will capture
- * the command event where you can write event handlers based on different command names.
- * The buttons' <b>CausesValidation</b> and <b>ValidationGroup</b> property values
- * are determined by the column's corresponding properties.
- *
- * The buttons in the column can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->ButtonColumnID->Button
- * $datagridItem->ButtonColumnID->Controls[0]
- * </code>
- * The second method is possible because the button control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TButtonColumn extends TDataGridColumn
-{
- /**
- * @return string the text caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the button.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the button caption
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the button caption
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the button caption will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the button caption will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the URL of the image file for image buttons
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for image buttons
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the button image url
- */
- public function getDataImageUrlField()
- {
- return $this->getViewState('DataImageUrlField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the button image url
- */
- public function setDataImageUrlField($value)
- {
- $this->setViewState('DataImageUrlField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the button image url will be displayed.
- */
- public function getDataImageUrlFormatString()
- {
- return $this->getViewState('DataImageUrlFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the button image url will be displayed.
- */
- public function setDataImageUrlFormatString($value)
- {
- $this->setViewState('DataImageUrlFormatString',$value,'');
- }
-
- /**
- * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
- }
-
- /**
- * @param TButtonColumnType the type of command button
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
- }
-
- /**
- * @return string the command name associated with the <b>OnCommand</b> event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * Sets the command name associated with the <b>Command</b> event.
- * @param string the text caption to be set
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a command button within the cell.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $buttonType=$this->getButtonType();
- if($buttonType===TButtonColumnType::LinkButton)
- $button=new TLinkButton;
- else if($buttonType===TButtonColumnType::PushButton)
- $button=new TButton;
- else // image button
- {
- $button=new TImageButton;
- $button->setImageUrl($this->getImageUrl());
- }
- $button->setText($this->getText());
- $button->setCommandName($this->getCommandName());
- $button->setCausesValidation($this->getCausesValidation());
- $button->setValidationGroup($this->getValidationGroup());
- if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!==''))
- $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- $cell->getControls()->add($button);
- $cell->registerObject('Button',$button);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- if($sender instanceof IButtonControl)
- {
- if(($field=$this->getDataTextField())!=='')
- {
- $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
- $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
- $sender->setText($text);
- }
- if(($sender instanceof TImageButton) && ($field=$this->getDataImageUrlField())!=='')
- {
- $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
- $url=$this->formatDataValue($this->getDataImageUrlFormatString(),$value);
- $sender->setImageUrl($url);
- }
- }
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +Prado::using('System.Web.UI.WebControls.TButton'); +Prado::using('System.Web.UI.WebControls.TLinkButton'); +Prado::using('System.Web.UI.WebControls.TImageButton'); + +/** + * TButtonColumn class + * + * TButtonColumn contains a user-defined command button, such as Add or Remove, + * that corresponds with each row in the column. + * + * The caption of the buttons in the column is determined by {@link setText Text} + * and {@link setDataTextField DataTextField} properties. If both are present, + * the latter takes precedence. The {@link setDataTextField DataTextField} property + * refers to the name of the field in datasource whose value will be used as the button caption. + * If {@link setDataTextFormatString DataTextFormatString} is not empty, + * the value will be formatted before rendering. + * + * The buttons in the column can be set to display as hyperlinks or push buttons + * by setting the {@link setButtonType ButtonType} property. + * The {@link setCommandName CommandName} will assign its value to + * all button's <b>CommandName</b> property. The datagrid will capture + * the command event where you can write event handlers based on different command names. + * The buttons' <b>CausesValidation</b> and <b>ValidationGroup</b> property values + * are determined by the column's corresponding properties. + * + * The buttons in the column can be accessed by one of the following two methods: + * <code> + * $datagridItem->ButtonColumnID->Button + * $datagridItem->ButtonColumnID->Controls[0] + * </code> + * The second method is possible because the button control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TButtonColumn extends TDataGridColumn +{ + /** + * @return string the text caption of the button + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the button. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string the field name from the data source to bind to the button caption + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * @param string the field name from the data source to bind to the button caption + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the button caption will be displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the button caption will be displayed. + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string the URL of the image file for image buttons + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * @param string the URL of the image file for image buttons + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * @return string the field name from the data source to bind to the button image url + */ + public function getDataImageUrlField() + { + return $this->getViewState('DataImageUrlField',''); + } + + /** + * @param string the field name from the data source to bind to the button image url + */ + public function setDataImageUrlField($value) + { + $this->setViewState('DataImageUrlField',$value,''); + } + + /** + * @return string the formatting string used to control how the button image url will be displayed. + */ + public function getDataImageUrlFormatString() + { + return $this->getViewState('DataImageUrlFormatString',''); + } + + /** + * @param string the formatting string used to control how the button image url will be displayed. + */ + public function setDataImageUrlFormatString($value) + { + $this->setViewState('DataImageUrlFormatString',$value,''); + } + + /** + * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton. + */ + public function getButtonType() + { + return $this->getViewState('ButtonType',TButtonColumnType::LinkButton); + } + + /** + * @param TButtonColumnType the type of command button + */ + public function setButtonType($value) + { + $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton); + } + + /** + * @return string the command name associated with the <b>OnCommand</b> event. + */ + public function getCommandName() + { + return $this->getViewState('CommandName',''); + } + + /** + * Sets the command name associated with the <b>Command</b> event. + * @param string the text caption to be set + */ + public function setCommandName($value) + { + $this->setViewState('CommandName',$value,''); + } + + /** + * @return boolean whether postback event trigger by this button will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this button will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a command button within the cell. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + $buttonType=$this->getButtonType(); + if($buttonType===TButtonColumnType::LinkButton) + $button=new TLinkButton; + else if($buttonType===TButtonColumnType::PushButton) + $button=new TButton; + else // image button + { + $button=new TImageButton; + $button->setImageUrl($this->getImageUrl()); + } + $button->setText($this->getText()); + $button->setCommandName($this->getCommandName()); + $button->setCausesValidation($this->getCausesValidation()); + $button->setValidationGroup($this->getValidationGroup()); + if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!=='')) + $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + $cell->getControls()->add($button); + $cell->registerObject('Button',$button); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + if($sender instanceof IButtonControl) + { + if(($field=$this->getDataTextField())!=='') + { + $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field); + $text=$this->formatDataValue($this->getDataTextFormatString(),$value); + $sender->setText($text); + } + if(($sender instanceof TImageButton) && ($field=$this->getDataImageUrlField())!=='') + { + $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field); + $url=$this->formatDataValue($this->getDataImageUrlFormatString(),$value); + $sender->setImageUrl($url); + } + } + } +} + diff --git a/framework/Web/UI/WebControls/TCaptcha.php b/framework/Web/UI/WebControls/TCaptcha.php index 7bcf5643..5ec870ce 100644 --- a/framework/Web/UI/WebControls/TCaptcha.php +++ b/framework/Web/UI/WebControls/TCaptcha.php @@ -1,495 +1,495 @@ -<?php
-/**
- * TCaptcha class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TCaptcha class.
- *
- * Notice: while this class is easy to use and implement, it does not provide full security.
- * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
- * A better alternative is provided by {@link TReCaptcha}.
- *
- * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used
- * to determine if the input is entered by a real user instead of some program.
- *
- * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie.
- *
- * The token (a string consisting of alphanumeric characters) displayed is automatically
- * generated and can be configured in several ways. To specify the length of characters
- * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}.
- * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive}
- * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
- * specifies what characters can appear in tokens.
- *
- * The validation of the token is related with two properties: {@link setTestLimit TestLimit}
- * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can
- * be tested with on the server side, and the latter says when a generated token will expire.
- *
- * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme}
- * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize}
- * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.)
- * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background
- * of the token will be variating even though the token is the same during postbacks.
- *
- * Upon postback, user input can be validated by calling {@link validate()}.
- * The {@link TCaptchaValidator} control can also be used to do validation, which provides
- * client-side validation besides the server-side validation. By default, the token will
- * remain the same during multiple postbacks. A new one can be generated by calling
- * {@link regenerateToken()} manually.
- *
- * The following template shows a typical use of TCaptcha control:
- * <code>
- * <com:TCaptcha ID="Captcha" />
- * <com:TTextBox ID="Input" />
- * <com:TCaptchaValidator CaptchaControl="Captcha"
- * ControlToValidate="Input"
- * ErrorMessage="You are challenged!" />
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TCaptcha extends TImage
-{
- const MIN_TOKEN_LENGTH=2;
- const MAX_TOKEN_LENGTH=40;
- private $_privateKey;
- private $_validated=false;
-
- /**
- * @return integer the theme of the token image. Defaults to 0.
- */
- public function getTokenImageTheme()
- {
- return $this->getViewState('TokenImageTheme',0);
- }
-
- /**
- * Sets the theme of the token image.
- * You may test each theme to find out the one you like the most.
- * Below is the explanation of the theme value:
- * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image.
- * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0).
- * Bit 1: whether we should add white noise to the image (1) or not (0).
- * Bit 2: whether we should add a grid to the image (1) or not (0).
- * Bit 3: whether we should add some scribbles to the image (1) or not (0).
- * Bit 4: whether the image background should be morphed (1) or not (0).
- * Bit 5: whether the token text should cast a shadow (1) or not (0).
- * @param integer the theme of the token image. It must be an integer between 0 and 63.
- */
- public function setTokenImageTheme($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value>=0 && $value<=63)
- $this->setViewState('TokenImageTheme',$value,0);
- else
- throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63);
- }
-
- /**
- * @return integer the font size used for displaying the token in an image. Defaults to 30.
- */
- public function getTokenFontSize()
- {
- return $this->getViewState('TokenFontSize',30);
- }
-
- /**
- * Sets the font size used for displaying the token in an image.
- * This property affects the generated token image size.
- * The image width is proportional to this font size.
- * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100.
- */
- public function setTokenFontSize($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value>=20 && $value<=100)
- $this->setViewState('TokenFontSize',$value,30);
- else
- throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100);
- }
-
- /**
- * @return integer the minimum length of the token. Defaults to 4.
- */
- public function getMinTokenLength()
- {
- return $this->getViewState('MinTokenLength',4);
- }
-
- /**
- * @param integer the minimum length of the token. It must be between 2 and 40.
- */
- public function setMinTokenLength($value)
- {
- $length=TPropertyValue::ensureInteger($value);
- if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MinTokenLength',$length,4);
- else
- throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
- }
-
- /**
- * @return integer the maximum length of the token. Defaults to 6.
- */
- public function getMaxTokenLength()
- {
- return $this->getViewState('MaxTokenLength',6);
- }
-
- /**
- * @param integer the maximum length of the token. It must be between 2 and 40.
- */
- public function setMaxTokenLength($value)
- {
- $length=TPropertyValue::ensureInteger($value);
- if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MaxTokenLength',$length,6);
- else
- throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
- }
-
- /**
- * @return boolean whether the token should be treated as case-sensitive. Defaults to true.
- */
- public function getCaseSensitive()
- {
- return $this->getViewState('CaseSensitive',true);
- }
-
- /**
- * @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token.
- */
- public function setCaseSensitive($value)
- {
- $this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'.
- */
- public function getTokenAlphabet()
- {
- return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT');
- }
-
- /**
- * @param string the characters that may appear in the token. At least 2 characters must be specified.
- */
- public function setTokenAlphabet($value)
- {
- if(strlen($value)<2)
- throw new TConfigurationException('captcha_tokenalphabet_invalid');
- $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT');
- }
-
- /**
- * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes).
- */
- public function getTokenExpiry()
- {
- return $this->getViewState('TokenExpiry',600);
- }
-
- /**
- * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire.
- */
- public function setTokenExpiry($value)
- {
- $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600);
- }
-
- /**
- * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false.
- */
- public function getChangingTokenBackground()
- {
- return $this->getViewState('ChangingTokenBackground',false);
- }
-
- /**
- * @param boolean whether the background of the token image should be variated during postbacks.
- */
- public function setChangingTokenBackground($value)
- {
- $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer how many times a generated token can be tested. Defaults to 5.
- */
- public function getTestLimit()
- {
- return $this->getViewState('TestLimit',5);
- }
-
- /**
- * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0.
- */
- public function setTestLimit($value)
- {
- $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5);
- }
-
- /**
- * @return boolean whether the currently generated token has expired.
- */
- public function getIsTokenExpired()
- {
- if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0)
- return $expiry+$start<time();
- else
- return false;
- }
-
- /**
- * @return string the public key used for generating the token. A random one will be generated and returned if this is not set.
- */
- public function getPublicKey()
- {
- if(($publicKey=$this->getViewState('PublicKey',''))==='')
- {
- $publicKey=$this->generateRandomKey();
- $this->setPublicKey($publicKey);
- }
- return $publicKey;
- }
-
- /**
- * @param string the public key used for generating the token. A random one will be generated if this is not set.
- */
- public function setPublicKey($value)
- {
- $this->setViewState('PublicKey',$value,'');
- }
-
- /**
- * @return string the token that will be displayed
- */
- public function getToken()
- {
- return $this->generateToken($this->getPublicKey(),$this->getPrivateKey(),$this->getTokenAlphabet(),$this->getTokenLength(),$this->getCaseSensitive());
- }
-
- /**
- * @return integer the length of the token to be generated.
- */
- protected function getTokenLength()
- {
- if(($tokenLength=$this->getViewState('TokenLength'))===null)
- {
- $minLength=$this->getMinTokenLength();
- $maxLength=$this->getMaxTokenLength();
- if($minLength>$maxLength)
- $tokenLength=rand($maxLength,$minLength);
- else if($minLength<$maxLength)
- $tokenLength=rand($minLength,$maxLength);
- else
- $tokenLength=$minLength;
- $this->setViewState('TokenLength',$tokenLength);
- }
- return $tokenLength;
- }
-
- /**
- * @return string the private key used for generating the token. This is randomly generated and kept in a file for persistency.
- */
- public function getPrivateKey()
- {
- if($this->_privateKey===null)
- {
- $fileName=$this->generatePrivateKeyFile();
- $content=file_get_contents($fileName);
- $matches=array();
- if(preg_match("/privateKey='(.*?)'/ms",$content,$matches)>0)
- $this->_privateKey=$matches[1];
- else
- throw new TConfigurationException('captcha_privatekey_unknown');
- }
- return $this->_privateKey;
- }
-
- /**
- * Validates a user input with the token.
- * @param string user input
- * @return boolean if the user input is not the same as the token.
- */
- public function validate($input)
- {
- $number=$this->getViewState('TestNumber',0);
- if(!$this->_validated)
- {
- $this->setViewState('TestNumber',++$number);
- $this->_validated=true;
- }
- if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit))
- {
- $this->regenerateToken();
- return false;
- }
- return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input)));
- }
-
- /**
- * Regenerates the token to be displayed.
- * By default, a token, once generated, will remain the same during the following page postbacks.
- * Calling this method will generate a new token.
- */
- public function regenerateToken()
- {
- $this->clearViewState('TokenLength');
- $this->setPublicKey('');
- $this->clearViewState('TokenGenerated');
- $this->clearViewState('RandomSeed');
- $this->clearViewState('TestNumber',0);
- }
-
- /**
- * Configures the image URL that shows the token.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if(!self::checkRequirements())
- throw new TConfigurationException('captcha_imagettftext_required');
- if(!$this->getViewState('TokenGenerated',0))
- {
- $manager=$this->getApplication()->getAssetManager();
- $manager->publishFilePath($this->getFontFile());
- $url=$manager->publishFilePath($this->getCaptchaScriptFile());
- $url.='?options='.urlencode($this->getTokenImageOptions());
- $this->setImageUrl($url);
-
- $this->setViewState('TokenGenerated',time());
- }
- }
-
- /**
- * @return string the options to be passed to the token image generator
- */
- protected function getTokenImageOptions()
- {
- $privateKey=$this->getPrivateKey(); // call this method to ensure private key is generated
- $token=$this->getToken();
- $options=array();
- $options['publicKey']=$this->getPublicKey();
- $options['tokenLength']=strlen($token);
- $options['caseSensitive']=$this->getCaseSensitive();
- $options['alphabet']=$this->getTokenAlphabet();
- $options['fontSize']=$this->getTokenFontSize();
- $options['theme']=$this->getTokenImageTheme();
- if(($randomSeed=$this->getViewState('RandomSeed',0))===0)
- {
- $randomSeed=(int)(microtime()*1000000);
- $this->setViewState('RandomSeed',$randomSeed);
- }
- $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed;
- $str=serialize($options);
- return base64_encode(md5($privateKey.$str).$str);
- }
-
- /**
- * @return string the file path of the PHP script generating the token image
- */
- protected function getCaptchaScriptFile()
- {
- return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'captcha.php';
- }
-
- protected function getFontFile()
- {
- return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'verase.ttf';
- }
-
- /**
- * Generates a file with a randomly generated private key.
- * @return string the path of the file keeping the private key
- */
- protected function generatePrivateKeyFile()
- {
- $captchaScript=$this->getCaptchaScriptFile();
- $path=dirname($this->getApplication()->getAssetManager()->getPublishedPath($captchaScript));
- $fileName=$path.DIRECTORY_SEPARATOR.'captcha_key.php';
- if(!is_file($fileName))
- {
- @mkdir($path);
- $key=$this->generateRandomKey();
- $content="<?php
-\$privateKey='$key';
-?>";
- file_put_contents($fileName,$content);
- }
- return $fileName;
- }
-
- /**
- * @return string a randomly generated key
- */
- protected function generateRandomKey()
- {
- return md5(rand().rand().rand().rand());
- }
-
- /**
- * Generates the token.
- * @param string public key
- * @param string private key
- * @param integer the length of the token
- * @param boolean whether the token is case sensitive
- * @return string the token generated.
- */
- protected function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
- {
- $token=substr($this->hash2string(md5($publicKey.$privateKey),$alphabet).$this->hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
- return $caseSensitive?$token:strtoupper($token);
- }
-
- /**
- * Converts a hash string into a string with characters consisting of alphanumeric characters.
- * @param string the hexadecimal representation of the hash string
- * @param string the alphabet used to represent the converted string. If empty, it means '234578adefhijmnrtwyABDEFGHIJLMNQRTWY', which excludes those confusing characters.
- * @return string the converted string
- */
- protected function hash2string($hex,$alphabet='')
- {
- if(strlen($alphabet)<2)
- $alphabet='234578adefhijmnrtABDEFGHJLMNQRT';
- $hexLength=strlen($hex);
- $base=strlen($alphabet);
- $result='';
- for($i=0;$i<$hexLength;$i+=6)
- {
- $number=hexdec(substr($hex,$i,6));
- while($number)
- {
- $result.=$alphabet[$number%$base];
- $number=floor($number/$base);
- }
- }
- return $result;
- }
-
- /**
- * Checks the requirements needed for generating CAPTCHA images.
- * TCaptach requires GD2 with TrueType font support and PNG image support.
- * @return boolean whether the requirements are satisfied.
- */
- public static function checkRequirements()
- {
- return extension_loaded('gd') && function_exists('imagettftext') && function_exists('imagepng');
- }
-}
-
+<?php +/** + * TCaptcha class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TImage'); + +/** + * TCaptcha class. + * + * Notice: while this class is easy to use and implement, it does not provide full security. + * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). + * A better alternative is provided by {@link TReCaptcha}. + * + * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used + * to determine if the input is entered by a real user instead of some program. + * + * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie. + * + * The token (a string consisting of alphanumeric characters) displayed is automatically + * generated and can be configured in several ways. To specify the length of characters + * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}. + * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive} + * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which + * specifies what characters can appear in tokens. + * + * The validation of the token is related with two properties: {@link setTestLimit TestLimit} + * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can + * be tested with on the server side, and the latter says when a generated token will expire. + * + * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme} + * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize} + * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.) + * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background + * of the token will be variating even though the token is the same during postbacks. + * + * Upon postback, user input can be validated by calling {@link validate()}. + * The {@link TCaptchaValidator} control can also be used to do validation, which provides + * client-side validation besides the server-side validation. By default, the token will + * remain the same during multiple postbacks. A new one can be generated by calling + * {@link regenerateToken()} manually. + * + * The following template shows a typical use of TCaptcha control: + * <code> + * <com:TCaptcha ID="Captcha" /> + * <com:TTextBox ID="Input" /> + * <com:TCaptchaValidator CaptchaControl="Captcha" + * ControlToValidate="Input" + * ErrorMessage="You are challenged!" /> + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TCaptcha extends TImage +{ + const MIN_TOKEN_LENGTH=2; + const MAX_TOKEN_LENGTH=40; + private $_privateKey; + private $_validated=false; + + /** + * @return integer the theme of the token image. Defaults to 0. + */ + public function getTokenImageTheme() + { + return $this->getViewState('TokenImageTheme',0); + } + + /** + * Sets the theme of the token image. + * You may test each theme to find out the one you like the most. + * Below is the explanation of the theme value: + * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image. + * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0). + * Bit 1: whether we should add white noise to the image (1) or not (0). + * Bit 2: whether we should add a grid to the image (1) or not (0). + * Bit 3: whether we should add some scribbles to the image (1) or not (0). + * Bit 4: whether the image background should be morphed (1) or not (0). + * Bit 5: whether the token text should cast a shadow (1) or not (0). + * @param integer the theme of the token image. It must be an integer between 0 and 63. + */ + public function setTokenImageTheme($value) + { + $value=TPropertyValue::ensureInteger($value); + if($value>=0 && $value<=63) + $this->setViewState('TokenImageTheme',$value,0); + else + throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63); + } + + /** + * @return integer the font size used for displaying the token in an image. Defaults to 30. + */ + public function getTokenFontSize() + { + return $this->getViewState('TokenFontSize',30); + } + + /** + * Sets the font size used for displaying the token in an image. + * This property affects the generated token image size. + * The image width is proportional to this font size. + * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100. + */ + public function setTokenFontSize($value) + { + $value=TPropertyValue::ensureInteger($value); + if($value>=20 && $value<=100) + $this->setViewState('TokenFontSize',$value,30); + else + throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100); + } + + /** + * @return integer the minimum length of the token. Defaults to 4. + */ + public function getMinTokenLength() + { + return $this->getViewState('MinTokenLength',4); + } + + /** + * @param integer the minimum length of the token. It must be between 2 and 40. + */ + public function setMinTokenLength($value) + { + $length=TPropertyValue::ensureInteger($value); + if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH) + $this->setViewState('MinTokenLength',$length,4); + else + throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH); + } + + /** + * @return integer the maximum length of the token. Defaults to 6. + */ + public function getMaxTokenLength() + { + return $this->getViewState('MaxTokenLength',6); + } + + /** + * @param integer the maximum length of the token. It must be between 2 and 40. + */ + public function setMaxTokenLength($value) + { + $length=TPropertyValue::ensureInteger($value); + if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH) + $this->setViewState('MaxTokenLength',$length,6); + else + throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH); + } + + /** + * @return boolean whether the token should be treated as case-sensitive. Defaults to true. + */ + public function getCaseSensitive() + { + return $this->getViewState('CaseSensitive',true); + } + + /** + * @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token. + */ + public function setCaseSensitive($value) + { + $this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'. + */ + public function getTokenAlphabet() + { + return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT'); + } + + /** + * @param string the characters that may appear in the token. At least 2 characters must be specified. + */ + public function setTokenAlphabet($value) + { + if(strlen($value)<2) + throw new TConfigurationException('captcha_tokenalphabet_invalid'); + $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT'); + } + + /** + * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes). + */ + public function getTokenExpiry() + { + return $this->getViewState('TokenExpiry',600); + } + + /** + * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire. + */ + public function setTokenExpiry($value) + { + $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600); + } + + /** + * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false. + */ + public function getChangingTokenBackground() + { + return $this->getViewState('ChangingTokenBackground',false); + } + + /** + * @param boolean whether the background of the token image should be variated during postbacks. + */ + public function setChangingTokenBackground($value) + { + $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return integer how many times a generated token can be tested. Defaults to 5. + */ + public function getTestLimit() + { + return $this->getViewState('TestLimit',5); + } + + /** + * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0. + */ + public function setTestLimit($value) + { + $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5); + } + + /** + * @return boolean whether the currently generated token has expired. + */ + public function getIsTokenExpired() + { + if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0) + return $expiry+$start<time(); + else + return false; + } + + /** + * @return string the public key used for generating the token. A random one will be generated and returned if this is not set. + */ + public function getPublicKey() + { + if(($publicKey=$this->getViewState('PublicKey',''))==='') + { + $publicKey=$this->generateRandomKey(); + $this->setPublicKey($publicKey); + } + return $publicKey; + } + + /** + * @param string the public key used for generating the token. A random one will be generated if this is not set. + */ + public function setPublicKey($value) + { + $this->setViewState('PublicKey',$value,''); + } + + /** + * @return string the token that will be displayed + */ + public function getToken() + { + return $this->generateToken($this->getPublicKey(),$this->getPrivateKey(),$this->getTokenAlphabet(),$this->getTokenLength(),$this->getCaseSensitive()); + } + + /** + * @return integer the length of the token to be generated. + */ + protected function getTokenLength() + { + if(($tokenLength=$this->getViewState('TokenLength'))===null) + { + $minLength=$this->getMinTokenLength(); + $maxLength=$this->getMaxTokenLength(); + if($minLength>$maxLength) + $tokenLength=rand($maxLength,$minLength); + else if($minLength<$maxLength) + $tokenLength=rand($minLength,$maxLength); + else + $tokenLength=$minLength; + $this->setViewState('TokenLength',$tokenLength); + } + return $tokenLength; + } + + /** + * @return string the private key used for generating the token. This is randomly generated and kept in a file for persistency. + */ + public function getPrivateKey() + { + if($this->_privateKey===null) + { + $fileName=$this->generatePrivateKeyFile(); + $content=file_get_contents($fileName); + $matches=array(); + if(preg_match("/privateKey='(.*?)'/ms",$content,$matches)>0) + $this->_privateKey=$matches[1]; + else + throw new TConfigurationException('captcha_privatekey_unknown'); + } + return $this->_privateKey; + } + + /** + * Validates a user input with the token. + * @param string user input + * @return boolean if the user input is not the same as the token. + */ + public function validate($input) + { + $number=$this->getViewState('TestNumber',0); + if(!$this->_validated) + { + $this->setViewState('TestNumber',++$number); + $this->_validated=true; + } + if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit)) + { + $this->regenerateToken(); + return false; + } + return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input))); + } + + /** + * Regenerates the token to be displayed. + * By default, a token, once generated, will remain the same during the following page postbacks. + * Calling this method will generate a new token. + */ + public function regenerateToken() + { + $this->clearViewState('TokenLength'); + $this->setPublicKey(''); + $this->clearViewState('TokenGenerated'); + $this->clearViewState('RandomSeed'); + $this->clearViewState('TestNumber',0); + } + + /** + * Configures the image URL that shows the token. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if(!self::checkRequirements()) + throw new TConfigurationException('captcha_imagettftext_required'); + if(!$this->getViewState('TokenGenerated',0)) + { + $manager=$this->getApplication()->getAssetManager(); + $manager->publishFilePath($this->getFontFile()); + $url=$manager->publishFilePath($this->getCaptchaScriptFile()); + $url.='?options='.urlencode($this->getTokenImageOptions()); + $this->setImageUrl($url); + + $this->setViewState('TokenGenerated',time()); + } + } + + /** + * @return string the options to be passed to the token image generator + */ + protected function getTokenImageOptions() + { + $privateKey=$this->getPrivateKey(); // call this method to ensure private key is generated + $token=$this->getToken(); + $options=array(); + $options['publicKey']=$this->getPublicKey(); + $options['tokenLength']=strlen($token); + $options['caseSensitive']=$this->getCaseSensitive(); + $options['alphabet']=$this->getTokenAlphabet(); + $options['fontSize']=$this->getTokenFontSize(); + $options['theme']=$this->getTokenImageTheme(); + if(($randomSeed=$this->getViewState('RandomSeed',0))===0) + { + $randomSeed=(int)(microtime()*1000000); + $this->setViewState('RandomSeed',$randomSeed); + } + $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed; + $str=serialize($options); + return base64_encode(md5($privateKey.$str).$str); + } + + /** + * @return string the file path of the PHP script generating the token image + */ + protected function getCaptchaScriptFile() + { + return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'captcha.php'; + } + + protected function getFontFile() + { + return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'verase.ttf'; + } + + /** + * Generates a file with a randomly generated private key. + * @return string the path of the file keeping the private key + */ + protected function generatePrivateKeyFile() + { + $captchaScript=$this->getCaptchaScriptFile(); + $path=dirname($this->getApplication()->getAssetManager()->getPublishedPath($captchaScript)); + $fileName=$path.DIRECTORY_SEPARATOR.'captcha_key.php'; + if(!is_file($fileName)) + { + @mkdir($path); + $key=$this->generateRandomKey(); + $content="<?php +\$privateKey='$key'; +?>"; + file_put_contents($fileName,$content); + } + return $fileName; + } + + /** + * @return string a randomly generated key + */ + protected function generateRandomKey() + { + return md5(rand().rand().rand().rand()); + } + + /** + * Generates the token. + * @param string public key + * @param string private key + * @param integer the length of the token + * @param boolean whether the token is case sensitive + * @return string the token generated. + */ + protected function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive) + { + $token=substr($this->hash2string(md5($publicKey.$privateKey),$alphabet).$this->hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength); + return $caseSensitive?$token:strtoupper($token); + } + + /** + * Converts a hash string into a string with characters consisting of alphanumeric characters. + * @param string the hexadecimal representation of the hash string + * @param string the alphabet used to represent the converted string. If empty, it means '234578adefhijmnrtwyABDEFGHIJLMNQRTWY', which excludes those confusing characters. + * @return string the converted string + */ + protected function hash2string($hex,$alphabet='') + { + if(strlen($alphabet)<2) + $alphabet='234578adefhijmnrtABDEFGHJLMNQRT'; + $hexLength=strlen($hex); + $base=strlen($alphabet); + $result=''; + for($i=0;$i<$hexLength;$i+=6) + { + $number=hexdec(substr($hex,$i,6)); + while($number) + { + $result.=$alphabet[$number%$base]; + $number=floor($number/$base); + } + } + return $result; + } + + /** + * Checks the requirements needed for generating CAPTCHA images. + * TCaptach requires GD2 with TrueType font support and PNG image support. + * @return boolean whether the requirements are satisfied. + */ + public static function checkRequirements() + { + return extension_loaded('gd') && function_exists('imagettftext') && function_exists('imagepng'); + } +} + diff --git a/framework/Web/UI/WebControls/TCaptchaValidator.php b/framework/Web/UI/WebControls/TCaptchaValidator.php index 9eca42fb..23943971 100644 --- a/framework/Web/UI/WebControls/TCaptchaValidator.php +++ b/framework/Web/UI/WebControls/TCaptchaValidator.php @@ -1,127 +1,127 @@ -<?php
-/**
- * TCaptchaValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-Prado::using('System.Web.UI.WebControls.TCaptcha');
-
-/**
- * TCaptchaValidator class
- *
- * Notice: while this class is easy to use and implement, it does not provide full security.
- * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
- * A better alternative is provided by {@link TReCaptchaValidator}.
- *
- * TCaptchaValidator validates user input against a CAPTCHA represented by
- * a {@link TCaptcha} control. The input control fails validation if its value
- * is not the same as the token displayed in CAPTCHA. Note, if the user does
- * not enter any thing, it is still considered as failing the validation.
- *
- * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
- * to be the ID path of the input control (usually a {@link TTextBox} control}.
- * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
- * the CAPTCHA control that the user input should be compared with.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TCaptchaValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCaptchaValidator';
- }
-
- /**
- * @return string the ID path of the CAPTCHA control to validate
- */
- public function getCaptchaControl()
- {
- return $this->getViewState('CaptchaControl','');
- }
-
- /**
- * Sets the ID path of the CAPTCHA control to validate.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the validator's naming container to the target control.
- * @param string the ID path
- */
- public function setCaptchaControl($value)
- {
- $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input control has the same value
- * as the one displayed in the corresponding CAPTCHA control.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $value=$this->getValidationValue($this->getValidationTarget());
- $control=$this->findCaptchaControl();
- return $control->validate(trim($value));
- }
-
- /**
- * @return TCaptchaControl the CAPTCHA control to be validated against
- * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
- */
- protected function findCaptchaControl()
- {
- if(($id=$this->getCaptchaControl())==='')
- throw new TConfigurationException('captchavalidator_captchacontrol_required');
- else if(($control=$this->findControl($id))===null)
- throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
- else if(!($control instanceof TCaptcha))
- throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
- else
- return $control;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- $control=$this->findCaptchaControl();
- if($control->getCaseSensitive())
- {
- $options['TokenHash']=$this->generateTokenHash($control->getToken());
- $options['CaseSensitive']=true;
- }
- else
- {
- $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
- $options['CaseSensitive']=false;
- }
- return $options;
- }
-
- private function generateTokenHash($token)
- {
- for($h=0,$i=strlen($token)-1;$i>=0;--$i)
- $h+=ord($token[$i]);
- return $h;
- }
-}
-
+<?php +/** + * TCaptchaValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TBaseValidator'); +Prado::using('System.Web.UI.WebControls.TCaptcha'); + +/** + * TCaptchaValidator class + * + * Notice: while this class is easy to use and implement, it does not provide full security. + * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack). + * A better alternative is provided by {@link TReCaptchaValidator}. + * + * TCaptchaValidator validates user input against a CAPTCHA represented by + * a {@link TCaptcha} control. The input control fails validation if its value + * is not the same as the token displayed in CAPTCHA. Note, if the user does + * not enter any thing, it is still considered as failing the validation. + * + * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate} + * to be the ID path of the input control (usually a {@link TTextBox} control}. + * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of + * the CAPTCHA control that the user input should be compared with. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TCaptchaValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCaptchaValidator'; + } + + /** + * @return string the ID path of the CAPTCHA control to validate + */ + public function getCaptchaControl() + { + return $this->getViewState('CaptchaControl',''); + } + + /** + * Sets the ID path of the CAPTCHA control to validate. + * The ID path is the dot-connected IDs of the controls reaching from + * the validator's naming container to the target control. + * @param string the ID path + */ + public function setCaptchaControl($value) + { + $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input control has the same value + * as the one displayed in the corresponding CAPTCHA control. + * + * @return boolean whether the validation succeeds + */ + protected function evaluateIsValid() + { + $value=$this->getValidationValue($this->getValidationTarget()); + $control=$this->findCaptchaControl(); + return $control->validate(trim($value)); + } + + /** + * @return TCaptchaControl the CAPTCHA control to be validated against + * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl} + */ + protected function findCaptchaControl() + { + if(($id=$this->getCaptchaControl())==='') + throw new TConfigurationException('captchavalidator_captchacontrol_required'); + else if(($control=$this->findControl($id))===null) + throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id); + else if(!($control instanceof TCaptcha)) + throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id); + else + return $control; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options=parent::getClientScriptOptions(); + $control=$this->findCaptchaControl(); + if($control->getCaseSensitive()) + { + $options['TokenHash']=$this->generateTokenHash($control->getToken()); + $options['CaseSensitive']=true; + } + else + { + $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken())); + $options['CaseSensitive']=false; + } + return $options; + } + + private function generateTokenHash($token) + { + for($h=0,$i=strlen($token)-1;$i>=0;--$i) + $h+=ord($token[$i]); + return $h; + } +} + diff --git a/framework/Web/UI/WebControls/TCheckBox.php b/framework/Web/UI/WebControls/TCheckBox.php index 641497ac..fe8bfbca 100644 --- a/framework/Web/UI/WebControls/TCheckBox.php +++ b/framework/Web/UI/WebControls/TCheckBox.php @@ -1,131 +1,131 @@ -<?php
-/**
- * TCheckBox class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TCheckBox class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TCheckBox class
- *
- * TCheckBox displays a check box on the page.
- * You can specify the caption to display beside the check box by setting
- * the {@link setText Text} property. The caption can appear either on the right
- * or left of the check box, which is determined by the {@link setTextAlign TextAlign}
- * property.
- *
- * To determine whether the TCheckBox component is checked, test the {@link getChecked Checked}
- * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
- * the {@link getChecked Checked} state of the TCheckBox component changes
- * between posts to the server. You can provide an event handler for
- * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
- * control the actions performed when the state of the TCheckBox component changes
- * between posts to the server.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, changing the check box state
- * will cause postback action. And if {@link setCausesValidation CausesValidation}
- * is true, validation will also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
- * that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer, ISurroundable
-{
- private $_dataChanged=false;
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TCheckBox class + * + * TCheckBox displays a check box on the page. + * You can specify the caption to display beside the check box by setting + * the {@link setText Text} property. The caption can appear either on the right + * or left of the check box, which is determined by the {@link setTextAlign TextAlign} + * property. + * + * To determine whether the TCheckBox component is checked, test the {@link getChecked Checked} + * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when + * the {@link getChecked Checked} state of the TCheckBox component changes + * between posts to the server. You can provide an event handler for + * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically + * control the actions performed when the state of the TCheckBox component changes + * between posts to the server. + * + * If {@link setAutoPostBack AutoPostBack} is set true, changing the check box state + * will cause postback action. And if {@link setCausesValidation CausesValidation} + * is true, validation will also be processed, which can be further restricted within + * a {@link setValidationGroup ValidationGroup}. + * + * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters + * that may bring security vulnerabilities. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer, ISurroundable +{ + private $_dataChanged=false; private $_isValid=true; -
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- $checked=$this->getChecked();
- if($newChecked=isset($values[$key]))
- $this->setValue($values[$key]);
- $this->setChecked($newChecked);
- return $this->_dataChanged=($newChecked!==$checked);
- }
-
- /**
- * Raises postdata changed event.
- * This method raises {@link onCheckedChanged OnCheckedChanged} event.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onCheckedChanged(null);
- }
-
- /**
- * Raises <b>OnCheckedChanged</b> event when {@link getChecked Checked} changes value during postback.
- * If you override this method, be sure to call the parent implementation
- * so that the event delegates can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onCheckedChanged($param)
- {
- $this->raiseEvent('OnCheckedChanged',$this,$param);
- }
-
- /**
- * Registers the checkbox to receive postback data during postback.
- * This is necessary because a checkbox if unchecked, when postback,
- * does not have direct mapping between post data and the checkbox name.
- *
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value of the property that needs validation.
- * @return mixed the property value to be validated
- */
- public function getValidationPropertyValue()
- {
- return $this->getChecked();
- }
-
+ + /** + * @return string tag name of the button + */ + protected function getTagName() + { + return 'input'; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + $checked=$this->getChecked(); + if($newChecked=isset($values[$key])) + $this->setValue($values[$key]); + $this->setChecked($newChecked); + return $this->_dataChanged=($newChecked!==$checked); + } + + /** + * Raises postdata changed event. + * This method raises {@link onCheckedChanged OnCheckedChanged} event. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onCheckedChanged(null); + } + + /** + * Raises <b>OnCheckedChanged</b> event when {@link getChecked Checked} changes value during postback. + * If you override this method, be sure to call the parent implementation + * so that the event delegates can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onCheckedChanged($param) + { + $this->raiseEvent('OnCheckedChanged',$this,$param); + } + + /** + * Registers the checkbox to receive postback data during postback. + * This is necessary because a checkbox if unchecked, when postback, + * does not have direct mapping between post data and the checkbox name. + * + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getEnabled(true)) + $this->getPage()->registerRequiresPostData($this); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the value of the property that needs validation. + * @return mixed the property value to be validated + */ + public function getValidationPropertyValue() + { + return $this->getChecked(); + } + /** * Returns true if this control validated successfully. * Defaults to true. @@ -143,390 +143,390 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl $this->_isValid=TPropertyValue::ensureBoolean($value); } - /**
- * @return string the text caption of the checkbox
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the checkbox.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the value of the checkbox. Defaults to empty.
- */
- public function getValue()
- {
- return $this->getViewState('Value','');
- }
-
- /**
- * @param string the value of the checkbox
- */
- public function setValue($value)
- {
- $this->setViewState('Value',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return TTextAlign the alignment (Left or Right) of the text caption, defaults to TTextAlign::Right.
- */
- public function getTextAlign()
- {
- return $this->getViewState('TextAlign',TTextAlign::Right);
- }
-
- /**
- * @param TTextAlign the alignment of the text caption. Valid values include Left and Right.
- */
- public function setTextAlign($value)
- {
- $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
- }
-
- /**
- * @return boolean whether the checkbox is checked
- */
- public function getChecked()
- {
- return $this->getViewState('Checked',false);
- }
-
- /**
- * Sets a value indicating whether the checkbox is to be checked or not.
- * @param boolean whether the checkbox is to be checked or not.
- */
- public function setChecked($value)
- {
- $this->setViewState('Checked',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Returns the value indicating whether the checkbox is checked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getChecked()}.
- * @return boolean whether the checkbox is checked.
- * @see getChecked
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getChecked();
- }
-
- /**
- * Sets the value indicating whether the checkbox is to be checked or not.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setChecked()}.
- * @param boolean whether the checkbox is to be checked
- * @see setChecked
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setChecked($value);
- }
-
- /**
- * @return boolean whether clicking on the checkbox will post the page.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets a value indicating whether clicking on the checkbox will post the page.
- * @param boolean whether clicking on the checkbox will post the page.
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event triggered by this checkbox will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * Sets the value indicating whether postback event trigger by this checkbox will cause input validation.
- * @param boolean whether postback event trigger by this checkbox will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the checkbox causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the checkbox causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the id of the surrounding tag or this clientID if no such tag needed
- */
- public function getSurroundingTagID()
- {
- return $this->getSpanNeeded() ? $this->getClientID().'_parent' : $this->getClientID();
- }
-
- /**
- * Renders the checkbox control.
- * This method overrides the parent implementation by rendering a checkbox input element
- * and a span element if needed.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $this->getPage()->ensureRenderInForm($this);
- if($this->getHasStyle())
- $this->getStyle()->addAttributesToRender($writer);
- if(($tooltip=$this->getToolTip())!=='')
- $writer->addAttribute('title',$tooltip);
- if($this->getHasAttributes())
- {
- $attributes=$this->getAttributes();
- $value=$attributes->remove('value');
- // onclick js should only be added to input tag
- if(($onclick=$attributes->remove('onclick'))===null)
- $onclick='';
- if($attributes->getCount())
- $writer->addAttributes($attributes);
- if($value!==null)
- $attributes->add('value',$value);
- }
- else
- $onclick='';
- if($needspan=$this->getSpanNeeded())
- {
- $writer->addAttribute('id',$this->getSurroundingTagID());
- $writer->renderBeginTag('span');
- }
- $clientID=$this->getClientID();
- if(($text=$this->getText())!=='')
- {
- if($this->getTextAlign()===TTextAlign::Left)
- {
- $this->renderLabel($writer,$clientID,$text);
- $this->renderInputTag($writer,$clientID,$onclick);
- }
- else
- {
- $this->renderInputTag($writer,$clientID,$onclick);
- $this->renderLabel($writer,$clientID,$text);
- }
- }
- else
- $this->renderInputTag($writer,$clientID,$onclick);
- if($needspan)
- $writer->renderEndTag();
- }
-
- /**
- * @return TMap list of attributes to be rendered for label beside the checkbox
- */
- public function getLabelAttributes()
- {
- if($attributes=$this->getViewState('LabelAttributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('LabelAttributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return TMap list of attributes to be rendered for the checkbox
- */
- public function getInputAttributes()
- {
- if($attributes=$this->getViewState('InputAttributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('InputAttributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return string the value attribute to be rendered
- */
- protected function getValueAttribute()
- {
- if(($value=$this->getValue())!=='')
- return $value;
- else
- {
- $attributes=$this->getViewState('InputAttributes',null);
- if($attributes && $attributes->contains('value'))
- return $attributes->itemAt('value');
- else if($this->hasAttribute('value'))
- return $this->getAttribute('value');
- else
- return '';
- }
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Check if we need a span tag to surround this control. The span tag will be created if
- * the Text property is set for this control.
- *
- * @return bool wether this control needs a surrounding span tag
- */
- protected function getSpanNeeded() {
- return $this->getText()!=='';
- }
-
- /**
- * Renders a label beside the checkbox.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string label text
- */
- protected function renderLabel($writer,$clientID,$text)
- {
- $writer->addAttribute('for',$clientID);
- if($attributes=$this->getViewState('LabelAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('label');
- $writer->write($text);
- $writer->renderEndTag();
- }
-
- /**
- * Renders a checkbox input element.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string onclick js
- */
- protected function renderInputTag($writer,$clientID,$onclick)
- {
- if($clientID!=='')
- $writer->addAttribute('id',$clientID);
- $writer->addAttribute('type','checkbox');
- if(($value=$this->getValueAttribute())!=='')
- $writer->addAttribute('value',$value);
- if(!empty($onclick))
- $writer->addAttribute('onclick',$onclick);
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getChecked())
- $writer->addAttribute('checked','checked');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
-
- $page=$this->getPage();
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
-
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- if(($tabindex=$this->getTabIndex())>0)
- $writer->addAttribute('tabindex',"$tabindex");
- if($attributes=$this->getViewState('InputAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCheckBox';
- }
-
- /**
- * Gets the post back options for this checkbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-}
-
-/**
- * TTextAlign class.
- * TTextAlign defines the enumerable type for the possible text alignments
- *
- * The following enumerable values are defined:
- * - Left: left aligned
- * - Right: right aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextAlign extends TEnumerable
-{
- const Left='Left';
- const Right='Right';
-}
-
-?>
+ /** + * @return string the text caption of the checkbox + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the checkbox. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string the value of the checkbox. Defaults to empty. + */ + public function getValue() + { + return $this->getViewState('Value',''); + } + + /** + * @param string the value of the checkbox + */ + public function setValue($value) + { + $this->setViewState('Value',TPropertyValue::ensureString($value),''); + } + + /** + * @return TTextAlign the alignment (Left or Right) of the text caption, defaults to TTextAlign::Right. + */ + public function getTextAlign() + { + return $this->getViewState('TextAlign',TTextAlign::Right); + } + + /** + * @param TTextAlign the alignment of the text caption. Valid values include Left and Right. + */ + public function setTextAlign($value) + { + $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right); + } + + /** + * @return boolean whether the checkbox is checked + */ + public function getChecked() + { + return $this->getViewState('Checked',false); + } + + /** + * Sets a value indicating whether the checkbox is to be checked or not. + * @param boolean whether the checkbox is to be checked or not. + */ + public function setChecked($value) + { + $this->setViewState('Checked',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Returns the value indicating whether the checkbox is checked. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getChecked()}. + * @return boolean whether the checkbox is checked. + * @see getChecked + * @since 3.1.0 + */ + public function getData() + { + return $this->getChecked(); + } + + /** + * Sets the value indicating whether the checkbox is to be checked or not. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setChecked()}. + * @param boolean whether the checkbox is to be checked + * @see setChecked + * @since 3.1.0 + */ + public function setData($value) + { + $this->setChecked($value); + } + + /** + * @return boolean whether clicking on the checkbox will post the page. + */ + public function getAutoPostBack() + { + return $this->getViewState('AutoPostBack',false); + } + + /** + * Sets a value indicating whether clicking on the checkbox will post the page. + * @param boolean whether clicking on the checkbox will post the page. + */ + public function setAutoPostBack($value) + { + $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether postback event triggered by this checkbox will cause input validation, default is true. + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * Sets the value indicating whether postback event trigger by this checkbox will cause input validation. + * @param boolean whether postback event trigger by this checkbox will cause input validation. + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the checkbox causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the checkbox causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return string the id of the surrounding tag or this clientID if no such tag needed + */ + public function getSurroundingTagID() + { + return $this->getSpanNeeded() ? $this->getClientID().'_parent' : $this->getClientID(); + } + + /** + * Renders the checkbox control. + * This method overrides the parent implementation by rendering a checkbox input element + * and a span element if needed. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + $this->getPage()->ensureRenderInForm($this); + if($this->getHasStyle()) + $this->getStyle()->addAttributesToRender($writer); + if(($tooltip=$this->getToolTip())!=='') + $writer->addAttribute('title',$tooltip); + if($this->getHasAttributes()) + { + $attributes=$this->getAttributes(); + $value=$attributes->remove('value'); + // onclick js should only be added to input tag + if(($onclick=$attributes->remove('onclick'))===null) + $onclick=''; + if($attributes->getCount()) + $writer->addAttributes($attributes); + if($value!==null) + $attributes->add('value',$value); + } + else + $onclick=''; + if($needspan=$this->getSpanNeeded()) + { + $writer->addAttribute('id',$this->getSurroundingTagID()); + $writer->renderBeginTag('span'); + } + $clientID=$this->getClientID(); + if(($text=$this->getText())!=='') + { + if($this->getTextAlign()===TTextAlign::Left) + { + $this->renderLabel($writer,$clientID,$text); + $this->renderInputTag($writer,$clientID,$onclick); + } + else + { + $this->renderInputTag($writer,$clientID,$onclick); + $this->renderLabel($writer,$clientID,$text); + } + } + else + $this->renderInputTag($writer,$clientID,$onclick); + if($needspan) + $writer->renderEndTag(); + } + + /** + * @return TMap list of attributes to be rendered for label beside the checkbox + */ + public function getLabelAttributes() + { + if($attributes=$this->getViewState('LabelAttributes',null)) + return $attributes; + else + { + $attributes=new TAttributeCollection; + $this->setViewState('LabelAttributes',$attributes,null); + return $attributes; + } + } + + /** + * @return TMap list of attributes to be rendered for the checkbox + */ + public function getInputAttributes() + { + if($attributes=$this->getViewState('InputAttributes',null)) + return $attributes; + else + { + $attributes=new TAttributeCollection; + $this->setViewState('InputAttributes',$attributes,null); + return $attributes; + } + } + + /** + * @return string the value attribute to be rendered + */ + protected function getValueAttribute() + { + if(($value=$this->getValue())!=='') + return $value; + else + { + $attributes=$this->getViewState('InputAttributes',null); + if($attributes && $attributes->contains('value')) + return $attributes->itemAt('value'); + else if($this->hasAttribute('value')) + return $this->getAttribute('value'); + else + return ''; + } + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Check if we need a span tag to surround this control. The span tag will be created if + * the Text property is set for this control. + * + * @return bool wether this control needs a surrounding span tag + */ + protected function getSpanNeeded() { + return $this->getText()!==''; + } + + /** + * Renders a label beside the checkbox. + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string label text + */ + protected function renderLabel($writer,$clientID,$text) + { + $writer->addAttribute('for',$clientID); + if($attributes=$this->getViewState('LabelAttributes',null)) + $writer->addAttributes($attributes); + $writer->renderBeginTag('label'); + $writer->write($text); + $writer->renderEndTag(); + } + + /** + * Renders a checkbox input element. + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string onclick js + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + if($clientID!=='') + $writer->addAttribute('id',$clientID); + $writer->addAttribute('type','checkbox'); + if(($value=$this->getValueAttribute())!=='') + $writer->addAttribute('value',$value); + if(!empty($onclick)) + $writer->addAttribute('onclick',$onclick); + if(($uniqueID=$this->getUniqueID())!=='') + $writer->addAttribute('name',$uniqueID); + if($this->getChecked()) + $writer->addAttribute('checked','checked'); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled','disabled'); + + $page=$this->getPage(); + if($this->getEnabled(true) + && $this->getEnableClientScript() + && $this->getAutoPostBack() + && $page->getClientSupportsJavaScript()) + { + $this->renderClientControlScript($writer); + } + + if(($accesskey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accesskey); + if(($tabindex=$this->getTabIndex())>0) + $writer->addAttribute('tabindex',"$tabindex"); + if($attributes=$this->getViewState('InputAttributes',null)) + $writer->addAttributes($attributes); + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * Renders the client-script code. + */ + protected function renderClientControlScript($writer) + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCheckBox'; + } + + /** + * Gets the post back options for this checkbox. + * @return array + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } +} + +/** + * TTextAlign class. + * TTextAlign defines the enumerable type for the possible text alignments + * + * The following enumerable values are defined: + * - Left: left aligned + * - Right: right aligned + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTextAlign extends TEnumerable +{ + const Left='Left'; + const Right='Right'; +} + +?> diff --git a/framework/Web/UI/WebControls/TCheckBoxColumn.php b/framework/Web/UI/WebControls/TCheckBoxColumn.php index 9c1db114..e1a2e178 100644 --- a/framework/Web/UI/WebControls/TCheckBoxColumn.php +++ b/framework/Web/UI/WebControls/TCheckBoxColumn.php @@ -1,123 +1,123 @@ -<?php
-/**
- * TCheckBoxColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TCheckBoxColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-/**
- * TCheckBox class file
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-
-/**
- * TCheckBoxColumn class
- *
- * TCheckBoxColumn represents a checkbox column that is bound to a field in a data source.
- * The checked state of the checkboxes are determiend by the bound data at
- * {@link setDataField DataField}. If {@link setReadOnly ReadOnly} is false,
- * TCheckBoxColumn will display an enabled checkbox provided the cells are
- * in edit mode. Otherwise, the checkboxes will be disabled to prevent from editting.
- *
- * The checkbox control in the TCheckBoxColumn can be accessed by one of
- * the following two methods:
- * <code>
- * $datagridItem->CheckBoxColumnID->CheckBox
- * $datagridItem->CheckBoxColumnID->Controls[0]
- * </code>
- * The second method is possible because the checkbox control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBoxColumn extends TDataGridColumn
-{
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a checkbox inside the cell.
- * If the column is read-only or if the item is not in edit mode,
- * the checkbox will be set disabled.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $checkBox=new TCheckBox;
- if($this->getReadOnly() || $itemType!==TListItemType::EditItem)
- $checkBox->setEnabled(false);
- $cell->setHorizontalAlign('Center');
- $cell->getControls()->add($checkBox);
- $cell->registerObject('CheckBox',$checkBox);
- if($this->getDataField()!=='')
- $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($field=$this->getDataField())!=='')
- $value=TPropertyValue::ensureBoolean($this->getDataFieldValue($data,$field));
- else
- $value=TPropertyValue::ensureBoolean($data);
- if($sender instanceof TCheckBox)
- $sender->setChecked($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +/** + * TCheckBox class file + */ +Prado::using('System.Web.UI.WebControls.TCheckBox'); + +/** + * TCheckBoxColumn class + * + * TCheckBoxColumn represents a checkbox column that is bound to a field in a data source. + * The checked state of the checkboxes are determiend by the bound data at + * {@link setDataField DataField}. If {@link setReadOnly ReadOnly} is false, + * TCheckBoxColumn will display an enabled checkbox provided the cells are + * in edit mode. Otherwise, the checkboxes will be disabled to prevent from editting. + * + * The checkbox control in the TCheckBoxColumn can be accessed by one of + * the following two methods: + * <code> + * $datagridItem->CheckBoxColumnID->CheckBox + * $datagridItem->CheckBoxColumnID->Controls[0] + * </code> + * The second method is possible because the checkbox control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCheckBoxColumn extends TDataGridColumn +{ + /** + * @return string the field name from the data source to bind to the column + */ + public function getDataField() + { + return $this->getViewState('DataField',''); + } + + /** + * @param string the field name from the data source to bind to the column + */ + public function setDataField($value) + { + $this->setViewState('DataField',$value,''); + } + + /** + * @return boolean whether the items in the column can be edited. Defaults to false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a checkbox inside the cell. + * If the column is read-only or if the item is not in edit mode, + * the checkbox will be set disabled. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + $checkBox=new TCheckBox; + if($this->getReadOnly() || $itemType!==TListItemType::EditItem) + $checkBox->setEnabled(false); + $cell->setHorizontalAlign('Center'); + $cell->getControls()->add($checkBox); + $cell->registerObject('CheckBox',$checkBox); + if($this->getDataField()!=='') + $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + if(($field=$this->getDataField())!=='') + $value=TPropertyValue::ensureBoolean($this->getDataFieldValue($data,$field)); + else + $value=TPropertyValue::ensureBoolean($data); + if($sender instanceof TCheckBox) + $sender->setChecked($value); + } +} + diff --git a/framework/Web/UI/WebControls/TCheckBoxList.php b/framework/Web/UI/WebControls/TCheckBoxList.php index 2f938174..3c298a02 100644 --- a/framework/Web/UI/WebControls/TCheckBoxList.php +++ b/framework/Web/UI/WebControls/TCheckBoxList.php @@ -1,499 +1,499 @@ -<?php
-/**
- * TCheckBoxList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-/**
- * Includes TRepeatInfo class
- */
-Prado::using('System.Web.UI.WebControls.TRepeatInfo');
-/**
- * Includes TCheckBox class
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-
-/**
- * TCheckBoxList class
- *
- * TCheckBoxList displays a list of checkboxes on a Web page.
- *
- * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout},
- * which can be either 'Table' (default) or 'Flow'.
- * A table layout uses HTML table cells to organize the checkboxes while
- * a flow layout uses line breaks to organize the checkboxes.
- * When the layout is using 'Table', {@link setCellPadding CellPadding} and
- * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and
- * cellpadding of the table.
- *
- * The number of columns used to display the checkboxes is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- *
- * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler, IValidatable
-{
- private $_repeatedControl;
- private $_isEnabled;
- private $_changedEventRaised=false;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * Constructor.
- * Remember to call parent implementation if you override this method
- */
- public function __construct()
- {
- parent::__construct();
- $this->_repeatedControl=$this->createRepeatedControl();
- $this->_repeatedControl->setEnableViewState(false);
- $this->_repeatedControl->setID('c0');
- $this->getControls()->add($this->_repeatedControl);
- }
-
- /**
- * Creates a control used for repetition (used as a template).
- * @return TControl the control to be repeated
- */
- protected function createRepeatedControl()
- {
- return new TCheckBox;
- }
-
- /**
- * Finds a control by ID.
- * This method overrides the parent implementation so that it always returns
- * the checkbox list itself (because the checkbox list does not have child controls.)
- * @param string control ID
- * @return TControl control being found
- */
- public function findControl($id)
- {
- return $this;
- }
-
- /**
- * @return boolean whether this control supports multiple selection. Always true for checkbox list.
- */
- protected function getIsMultiSelect()
- {
- return true;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by checkbox list.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return TTextAlign the alignment of the text caption, defaults to TTextAlign::Right.
- */
- public function getTextAlign()
- {
- return $this->getViewState('TextAlign',TTextAlign::Right);
- }
-
- /**
- * @param TTextAlign the text alignment of the checkboxes
- */
- public function setTextAlign($value)
- {
- $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
- }
-
-
- /**
- * @return TRepeatInfo repeat information (primarily used by control developers)
- */
- protected function getRepeatInfo()
- {
- if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
- {
- $repeatInfo=new TRepeatInfo;
- $this->setViewState('RepeatInfo',$repeatInfo,null);
- }
- return $repeatInfo;
- }
-
- /**
- * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->getRepeatInfo()->getRepeatColumns();
- }
-
- /**
- * @param integer the number of columns that the list should be displayed with.
- */
- public function setRepeatColumns($value)
- {
- $this->getRepeatInfo()->setRepeatColumns($value);
- }
-
- /**
- * @return string the direction of traversing the list, defaults to 'Vertical'
- */
- public function getRepeatDirection()
- {
- return $this->getRepeatInfo()->getRepeatDirection();
- }
-
- /**
- * @param string the direction (Vertical, Horizontal) of traversing the list
- */
- public function setRepeatDirection($value)
- {
- $this->getRepeatInfo()->setRepeatDirection($value);
- }
-
- /**
- * @return string how the list should be displayed, using table or using line breaks. Defaults to 'Table'.
- */
- public function getRepeatLayout()
- {
- return $this->getRepeatInfo()->getRepeatLayout();
- }
-
- /**
- * @param string how the list should be displayed, using table or using line breaks (Table, Flow)
- */
- public function setRepeatLayout($value)
- {
- $this->getRepeatInfo()->setRepeatLayout($value);
- }
-
- /**
- * @return integer the cellspacing for the table keeping the checkbox list. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * Sets the cellspacing for the table keeping the checkbox list.
- * @param integer the cellspacing for the table keeping the checkbox list.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table keeping the checkbox list. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * Sets the cellpadding for the table keeping the checkbox list.
- * @param integer the cellpadding for the table keeping the checkbox list.
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * Returns a value indicating whether this control contains header item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasHeader()
- {
- return false;
- }
-
- /**
- * Returns a value indicating whether this control contains footer item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasFooter()
- {
- return false;
- }
-
- /**
- * Returns a value indicating whether this control contains separator items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasSeparators()
- {
- return false;
- }
-
- /**
- * @param boolean whether the control is to be enabled.
- */
- public function setEnabled($value)
- {
- parent::setEnabled($value);
- $value = !TPropertyValue::ensureBoolean($value);
- // if this is an active control,
- // and it's a callback,
- // and we can update clientside,
- // then update the 'disabled' attribute of the items.
- if(($this instanceof IActiveControl) &&
- $this->getPage()->getIsCallBack() &&
- $this->getActiveControl()->canUpdateClientSide())
- {
- $items = $this->getItems();
- $cs = $this->getPage()->getCallbackClient();
- $baseClientID = $this->getClientID().'_c';
- foreach($items as $index=>$item)
- {
- $cs->setAttribute($baseClientID.$index, 'disabled', $value);
- }
- }
- }
-
- /**
- * Returns a style used for rendering items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer index of the item being rendered
- * @return null
- */
- public function generateItemStyle($itemType,$index)
- {
- return null;
- }
-
- /**
- * Renders an item in the list.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param THtmlWriter writer for rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the item in the item list
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index)
- {
- $repeatedControl=$this->_repeatedControl;
- $item=$this->getItems()->itemAt($index);
- if($item->getHasAttributes())
- $repeatedControl->getAttributes()->copyFrom($item->getAttributes());
- else if($repeatedControl->getHasAttributes())
- $repeatedControl->getAttributes()->clear();
- $repeatedControl->setID("c$index");
- $repeatedControl->setText($item->getText());
- $repeatedControl->setChecked($item->getSelected());
- $repeatedControl->setAttribute('value',$item->getValue());
- $repeatedControl->setEnabled($this->_isEnabled && $item->getEnabled());
- $repeatedControl->setEnableClientScript(false);
- $repeatedControl->renderControl($writer);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if($this->getEnabled(true))
- {
- $index=(int)substr($key,strlen($this->getUniqueID())+2);
- $this->ensureDataBound();
- if($index>=0 && $index<$this->getItemCount())
- {
- $item=$this->getItems()->itemAt($index);
- if($item->getEnabled())
- {
- $checked=isset($values[$key]);
- if($item->getSelected()!==$checked)
- {
- $item->setSelected($checked);
- if(!$this->_changedEventRaised)
- {
- $this->_changedEventRaised=true;
- return $this->_dataChanged=true;
- }
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Registers for post data on postback.
- * This method overrides the parent implementation.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->_repeatedControl->setAutoPostBack($this->getAutoPostBack());
- $this->_repeatedControl->setCausesValidation($this->getCausesValidation());
- $this->_repeatedControl->setValidationGroup($this->getValidationGroup());
- $page=$this->getPage();
- $n=$this->getItemCount();
- for($i=0;$i<$n;++$i)
- {
- $this->_repeatedControl->setID("c$i");
- $page->registerRequiresPostData($this->_repeatedControl);
- }
- }
-
- /**
- * Wether the list should be rendered inside a span or not
- *
- *@return boolean true if we need a span
- */
- protected function getSpanNeeded ()
- {
- return $this->getRepeatLayout()===TRepeatLayout::Raw;
- }
-
- /**
- * Renders the checkbox list control.
- * This method overrides the parent implementation.
- * @param THtmlWriter writer for rendering purpose.
- */
- public function render($writer)
- {
- if($this->getItemCount()>0)
- {
- if ($needSpan=$this->getSpanNeeded())
- {
- $writer->addAttribute('id', $this->getClientId());
- $writer->renderBeginTag('span');
- }
- $this->_isEnabled=$this->getEnabled(true);
- $repeatInfo=$this->getRepeatInfo();
- $accessKey=$this->getAccessKey();
- $tabIndex=$this->getTabIndex();
- $this->_repeatedControl->setTextAlign($this->getTextAlign());
- $this->_repeatedControl->setAccessKey($accessKey);
- $this->_repeatedControl->setTabIndex($tabIndex);
- $this->setAccessKey('');
- $this->setTabIndex(0);
- $repeatInfo->renderRepeater($writer,$this);
- $this->setAccessKey($accessKey);
- $this->setTabIndex($tabIndex);
- if ($needSpan)
- $writer->renderEndTag();
- }
- //checkbox skipped the client control script in addAttributesToRender
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $this->getPage()->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCheckBoxList';
- }
-
- /**
- * Gets the post back options for this checkbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ListID'] = $this->getClientID();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ListName'] = $this->getUniqueID();
- $options['ItemCount'] = $this->getItemCount();
- return $options;
- }
-
-}
-
+<?php +/** + * TCheckBoxList class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); +/** + * Includes TRepeatInfo class + */ +Prado::using('System.Web.UI.WebControls.TRepeatInfo'); +/** + * Includes TCheckBox class + */ +Prado::using('System.Web.UI.WebControls.TCheckBox'); + +/** + * TCheckBoxList class + * + * TCheckBoxList displays a list of checkboxes on a Web page. + * + * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout}, + * which can be either 'Table' (default) or 'Flow'. + * A table layout uses HTML table cells to organize the checkboxes while + * a flow layout uses line breaks to organize the checkboxes. + * When the layout is using 'Table', {@link setCellPadding CellPadding} and + * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and + * cellpadding of the table. + * + * The number of columns used to display the checkboxes is specified via + * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} + * governs the order of the items being rendered. + * + * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler, IValidatable +{ + private $_repeatedControl; + private $_isEnabled; + private $_changedEventRaised=false; + private $_dataChanged=false; + private $_isValid=true; + + /** + * Constructor. + * Remember to call parent implementation if you override this method + */ + public function __construct() + { + parent::__construct(); + $this->_repeatedControl=$this->createRepeatedControl(); + $this->_repeatedControl->setEnableViewState(false); + $this->_repeatedControl->setID('c0'); + $this->getControls()->add($this->_repeatedControl); + } + + /** + * Creates a control used for repetition (used as a template). + * @return TControl the control to be repeated + */ + protected function createRepeatedControl() + { + return new TCheckBox; + } + + /** + * Finds a control by ID. + * This method overrides the parent implementation so that it always returns + * the checkbox list itself (because the checkbox list does not have child controls.) + * @param string control ID + * @return TControl control being found + */ + public function findControl($id) + { + return $this; + } + + /** + * @return boolean whether this control supports multiple selection. Always true for checkbox list. + */ + protected function getIsMultiSelect() + { + return true; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableStyle} to be used by checkbox list. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableStyle; + } + + /** + * @return TTextAlign the alignment of the text caption, defaults to TTextAlign::Right. + */ + public function getTextAlign() + { + return $this->getViewState('TextAlign',TTextAlign::Right); + } + + /** + * @param TTextAlign the text alignment of the checkboxes + */ + public function setTextAlign($value) + { + $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right); + } + + + /** + * @return TRepeatInfo repeat information (primarily used by control developers) + */ + protected function getRepeatInfo() + { + if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null) + { + $repeatInfo=new TRepeatInfo; + $this->setViewState('RepeatInfo',$repeatInfo,null); + } + return $repeatInfo; + } + + /** + * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set. + */ + public function getRepeatColumns() + { + return $this->getRepeatInfo()->getRepeatColumns(); + } + + /** + * @param integer the number of columns that the list should be displayed with. + */ + public function setRepeatColumns($value) + { + $this->getRepeatInfo()->setRepeatColumns($value); + } + + /** + * @return string the direction of traversing the list, defaults to 'Vertical' + */ + public function getRepeatDirection() + { + return $this->getRepeatInfo()->getRepeatDirection(); + } + + /** + * @param string the direction (Vertical, Horizontal) of traversing the list + */ + public function setRepeatDirection($value) + { + $this->getRepeatInfo()->setRepeatDirection($value); + } + + /** + * @return string how the list should be displayed, using table or using line breaks. Defaults to 'Table'. + */ + public function getRepeatLayout() + { + return $this->getRepeatInfo()->getRepeatLayout(); + } + + /** + * @param string how the list should be displayed, using table or using line breaks (Table, Flow) + */ + public function setRepeatLayout($value) + { + $this->getRepeatInfo()->setRepeatLayout($value); + } + + /** + * @return integer the cellspacing for the table keeping the checkbox list. Defaults to -1, meaning not set. + */ + public function getCellSpacing() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellSpacing(); + else + return -1; + } + + /** + * Sets the cellspacing for the table keeping the checkbox list. + * @param integer the cellspacing for the table keeping the checkbox list. + */ + public function setCellSpacing($value) + { + $this->getStyle()->setCellSpacing($value); + } + + /** + * @return integer the cellpadding for the table keeping the checkbox list. Defaults to -1, meaning not set. + */ + public function getCellPadding() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellPadding(); + else + return -1; + } + + /** + * Sets the cellpadding for the table keeping the checkbox list. + * @param integer the cellpadding for the table keeping the checkbox list. + */ + public function setCellPadding($value) + { + $this->getStyle()->setCellPadding($value); + } + + /** + * Returns a value indicating whether this control contains header item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean always false. + */ + public function getHasHeader() + { + return false; + } + + /** + * Returns a value indicating whether this control contains footer item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean always false. + */ + public function getHasFooter() + { + return false; + } + + /** + * Returns a value indicating whether this control contains separator items. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean always false. + */ + public function getHasSeparators() + { + return false; + } + + /** + * @param boolean whether the control is to be enabled. + */ + public function setEnabled($value) + { + parent::setEnabled($value); + $value = !TPropertyValue::ensureBoolean($value); + // if this is an active control, + // and it's a callback, + // and we can update clientside, + // then update the 'disabled' attribute of the items. + if(($this instanceof IActiveControl) && + $this->getPage()->getIsCallBack() && + $this->getActiveControl()->canUpdateClientSide()) + { + $items = $this->getItems(); + $cs = $this->getPage()->getCallbackClient(); + $baseClientID = $this->getClientID().'_c'; + foreach($items as $index=>$item) + { + $cs->setAttribute($baseClientID.$index, 'disabled', $value); + } + } + } + + /** + * Returns a style used for rendering items. + * This method is required by {@link IRepeatInfoUser} interface. + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer index of the item being rendered + * @return null + */ + public function generateItemStyle($itemType,$index) + { + return null; + } + + /** + * Renders an item in the list. + * This method is required by {@link IRepeatInfoUser} interface. + * @param THtmlWriter writer for rendering purpose + * @param TRepeatInfo repeat information + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer zero-based index of the item in the item list + */ + public function renderItem($writer,$repeatInfo,$itemType,$index) + { + $repeatedControl=$this->_repeatedControl; + $item=$this->getItems()->itemAt($index); + if($item->getHasAttributes()) + $repeatedControl->getAttributes()->copyFrom($item->getAttributes()); + else if($repeatedControl->getHasAttributes()) + $repeatedControl->getAttributes()->clear(); + $repeatedControl->setID("c$index"); + $repeatedControl->setText($item->getText()); + $repeatedControl->setChecked($item->getSelected()); + $repeatedControl->setAttribute('value',$item->getValue()); + $repeatedControl->setEnabled($this->_isEnabled && $item->getEnabled()); + $repeatedControl->setEnableClientScript(false); + $repeatedControl->renderControl($writer); + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + if($this->getEnabled(true)) + { + $index=(int)substr($key,strlen($this->getUniqueID())+2); + $this->ensureDataBound(); + if($index>=0 && $index<$this->getItemCount()) + { + $item=$this->getItems()->itemAt($index); + if($item->getEnabled()) + { + $checked=isset($values[$key]); + if($item->getSelected()!==$checked) + { + $item->setSelected($checked); + if(!$this->_changedEventRaised) + { + $this->_changedEventRaised=true; + return $this->_dataChanged=true; + } + } + } + } + } + return false; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onSelectedIndexChanged(null); + } + + /** + * Registers for post data on postback. + * This method overrides the parent implementation. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->_repeatedControl->setAutoPostBack($this->getAutoPostBack()); + $this->_repeatedControl->setCausesValidation($this->getCausesValidation()); + $this->_repeatedControl->setValidationGroup($this->getValidationGroup()); + $page=$this->getPage(); + $n=$this->getItemCount(); + for($i=0;$i<$n;++$i) + { + $this->_repeatedControl->setID("c$i"); + $page->registerRequiresPostData($this->_repeatedControl); + } + } + + /** + * Wether the list should be rendered inside a span or not + * + *@return boolean true if we need a span + */ + protected function getSpanNeeded () + { + return $this->getRepeatLayout()===TRepeatLayout::Raw; + } + + /** + * Renders the checkbox list control. + * This method overrides the parent implementation. + * @param THtmlWriter writer for rendering purpose. + */ + public function render($writer) + { + if($this->getItemCount()>0) + { + if ($needSpan=$this->getSpanNeeded()) + { + $writer->addAttribute('id', $this->getClientId()); + $writer->renderBeginTag('span'); + } + $this->_isEnabled=$this->getEnabled(true); + $repeatInfo=$this->getRepeatInfo(); + $accessKey=$this->getAccessKey(); + $tabIndex=$this->getTabIndex(); + $this->_repeatedControl->setTextAlign($this->getTextAlign()); + $this->_repeatedControl->setAccessKey($accessKey); + $this->_repeatedControl->setTabIndex($tabIndex); + $this->setAccessKey(''); + $this->setTabIndex(0); + $repeatInfo->renderRepeater($writer,$this); + $this->setAccessKey($accessKey); + $this->setTabIndex($tabIndex); + if ($needSpan) + $writer->renderEndTag(); + } + //checkbox skipped the client control script in addAttributesToRender + if($this->getEnabled(true) + && $this->getEnableClientScript() + && $this->getAutoPostBack() + && $this->getPage()->getClientSupportsJavaScript()) + { + $this->renderClientControlScript($writer); + } + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getSelectedValue(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCheckBoxList'; + } + + /** + * Gets the post back options for this checkbox. + * @return array + */ + protected function getPostBackOptions() + { + $options['ListID'] = $this->getClientID(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ListName'] = $this->getUniqueID(); + $options['ItemCount'] = $this->getItemCount(); + return $options; + } + +} + diff --git a/framework/Web/UI/WebControls/TColorPicker.php b/framework/Web/UI/WebControls/TColorPicker.php index e5b24bd0..365421a1 100644 --- a/framework/Web/UI/WebControls/TColorPicker.php +++ b/framework/Web/UI/WebControls/TColorPicker.php @@ -1,290 +1,290 @@ -<?php
-/**
- * TColorPicker class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TColorPicker class.
- *
- * TColorPicker displays a text box for color input purpose.
- * Next to the textbox there's a button filled with the current chosen color.
- * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF).
- * Alternatively, if the <b>ShowColorPicker</b> property is enabled (it is by default), users can click the button
- * to have a color picker UI appear. A color chan be chosen directly by clicking on the color picker.
- *
- * TColorPicker has three different color picker UI <b>Mode</b>s:
- * # <b>Simple</b> - Grid with 12 simple colors.
- * # <b>Basic</b> - Grid with the most common 70 colors. This is the default mode.
- * # <b>Full</b> - Full-featured color picker.
- *
- * The <b>CssClass</b> property can be used to override the CSS class name
- * for the color picker panel. The <b>ColorStyle</b> property sets the packages
- * styles available. E.g. <b>default</b>.
- *
- * If the <b>Mode</b> property is set to <b>Full</b>, the color picker panel will
- * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the <b>OKButtonText</b>
- * and <b>CancelButtonText</b> properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TColorPicker extends TTextBox
-{
- const SCRIPT_PATH = 'prado/colorpicker';
-
- private $_clientSide;
-
- /**
- * @return boolean whether the color picker should pop up when the button is clicked.
- */
- public function getShowColorPicker()
- {
- return $this->getViewState('ShowColorPicker',true);
- }
-
- /**
- * Sets whether to pop up the color picker when the button is clicked.
- * @param boolean whether to show the color picker popup
- */
- public function setShowColorPicker($value)
- {
- $this->setViewState('ShowColorPicker',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @param TColorPickerMode color picker UI mode
- */
- public function setMode($value)
- {
- $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TColorPickerMode'), TColorPickerMode::Basic);
- }
-
- /**
- * @return TColorPickerMode current color picker UI mode. Defaults to TColorPickerMode::Basic.
- */
- public function getMode()
- {
- return $this->getViewState('Mode', TColorPickerMode::Basic);
- }
-
- /**
- * @param string set the color picker style
- */
- public function setColorPickerStyle($value)
- {
- $this->setViewState('ColorStyle', $value, 'default');
- }
-
- /**
- * @return string current color picker style
- */
- public function getColorPickerStyle()
- {
- return $this->getViewState('ColorStyle', 'default');
- }
-
- /**
- * @return string text for the color picker OK button. Default is "OK".
- */
- public function getOKButtonText()
- {
- return $this->getViewState('OKButtonText', 'OK');
- }
-
- /**
- * @param string text for the color picker OK button
- */
- public function setOKButtonText($value)
- {
- $this->setViewState('OKButtonText', $value, 'OK');
- }
-
- /**
- * @return string text for the color picker Cancel button. Default is "Cancel".
- */
- public function getCancelButtonText()
- {
- return $this->getViewState('CancelButtonText', 'Cancel');
- }
-
- /**
- * @param string text for the color picker Cancel button
- */
- public function setCancelButtonText($value)
- {
- $this->setViewState('CancelButtonText', $value, 'Cancel');
- }
-
- /**
- * @return TColorPickerClientSide javascript event options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientSide();
- return $this->_clientSide;
- }
-
- /**
- * @return TColorPickerClientSide javascript validator event options.
- */
- protected function createClientSide()
- {
- return new TColorPickerClientSide;
- }
-
- /**
- * Get javascript color picker options.
- * @return array color picker client-side options
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['ClassName'] = $this->getCssClass();
- $options['ShowColorPicker'] = $this->getShowColorPicker();
- if($options['ShowColorPicker'])
- {
- $mode = $this->getMode();
- if($mode == TColorPickerMode::Full) $options['Mode'] = $mode;
- else if($mode == TColorPickerMode::Simple) $options['Palette'] = 'Tiny';
- $options['OKButtonText'] = $this->getOKButtonText();
- $options['CancelButtonText'] = $this->getCancelButtonText();
- }
- $options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
- return $options;
- }
-
- /**
- * @param string asset file in the self::SCRIPT_PATH directory.
- * @return string asset file url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Publish the color picker Css asset files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->publishColorPickerAssets();
- }
-
- /**
- * Publish the color picker assets.
- */
- protected function publishColorPickerAssets()
- {
- $cs = $this->getPage()->getClientScript();
- $key = "prado:".get_class($this);
- $imgs['button.gif'] = $this->getAssetUrl('button.gif');
- $imgs['background.png'] = $this->getAssetUrl('background.png');
- $options = TJavaScript::encode($imgs);
- $code = "Prado.WebUI.TColorPicker.UIImages = {$options};";
- $cs->registerEndScript($key, $code);
- $cs->registerPradoScript("colorpicker");
- $url = $this->getAssetUrl($this->getColorPickerStyle().'.css');
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- }
-
- /**
- * Renders additional body content.
- * This method overrides parent implementation by adding
- * additional color picker button.
- * @param THtmlWriter writer
- */
- public function renderEndTag($writer)
- {
- parent::renderEndTag($writer);
-
- $color = $this->getText();
- $writer->addAttribute('class', 'TColorPicker_button');
- $writer->renderBeginTag('span');
-
- $writer->addAttribute('id', $this->getClientID().'_button');
- $writer->addAttribute('src', $this->getAssetUrl('button.gif'));
- if($color !== '')
- $writer->addAttribute('style', "background-color:{$color};");
- $writer->addAttribute('width', '20');
- $writer->addAttribute('height', '20');
- $writer->addAttribute('alt', '');
- $writer->renderBeginTag('img');
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TColorPicker';
- }
-}
-
-/**
- * TColorPickerMode class.
- * TColorPickerMode defines the enumerable type for the possible UI mode
- * that a {@link TColorPicker} control can take.
- *
- * The following enumerable values are defined:
- * # Simple - Grid with 12 simple colors.
- * # Basic - Grid with the most common 70 colors. This is the default mode.
- * # Full - Full-featured color picker.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TColorPickerMode extends TEnumerable
-{
- const Simple='Simple';
- const Basic='Basic';
- const Full='Full';
-}
-
-/**
- * TColorPickerClientSide class.
- *
- * Client-side javascript code options.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TColorPickerClientSide extends TClientSideOptions
-{
- /**
- * @return string javascript code for when a color is selected.
- */
- public function getOnColorSelected()
- {
- return $this->getOption('OnColorSelected');
- }
-
- /**
- * @param string javascript code for when a color is selected.
- */
- public function setOnColorSelected($javascript)
- {
- $this->setFunction('OnColorSelected', $javascript);
- }
-}
-
+<?php +/** + * TColorPicker class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TColorPicker class. + * + * TColorPicker displays a text box for color input purpose. + * Next to the textbox there's a button filled with the current chosen color. + * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF). + * Alternatively, if the <b>ShowColorPicker</b> property is enabled (it is by default), users can click the button + * to have a color picker UI appear. A color chan be chosen directly by clicking on the color picker. + * + * TColorPicker has three different color picker UI <b>Mode</b>s: + * # <b>Simple</b> - Grid with 12 simple colors. + * # <b>Basic</b> - Grid with the most common 70 colors. This is the default mode. + * # <b>Full</b> - Full-featured color picker. + * + * The <b>CssClass</b> property can be used to override the CSS class name + * for the color picker panel. The <b>ColorStyle</b> property sets the packages + * styles available. E.g. <b>default</b>. + * + * If the <b>Mode</b> property is set to <b>Full</b>, the color picker panel will + * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the <b>OKButtonText</b> + * and <b>CancelButtonText</b> properties. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TColorPicker extends TTextBox +{ + const SCRIPT_PATH = 'prado/colorpicker'; + + private $_clientSide; + + /** + * @return boolean whether the color picker should pop up when the button is clicked. + */ + public function getShowColorPicker() + { + return $this->getViewState('ShowColorPicker',true); + } + + /** + * Sets whether to pop up the color picker when the button is clicked. + * @param boolean whether to show the color picker popup + */ + public function setShowColorPicker($value) + { + $this->setViewState('ShowColorPicker',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @param TColorPickerMode color picker UI mode + */ + public function setMode($value) + { + $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TColorPickerMode'), TColorPickerMode::Basic); + } + + /** + * @return TColorPickerMode current color picker UI mode. Defaults to TColorPickerMode::Basic. + */ + public function getMode() + { + return $this->getViewState('Mode', TColorPickerMode::Basic); + } + + /** + * @param string set the color picker style + */ + public function setColorPickerStyle($value) + { + $this->setViewState('ColorStyle', $value, 'default'); + } + + /** + * @return string current color picker style + */ + public function getColorPickerStyle() + { + return $this->getViewState('ColorStyle', 'default'); + } + + /** + * @return string text for the color picker OK button. Default is "OK". + */ + public function getOKButtonText() + { + return $this->getViewState('OKButtonText', 'OK'); + } + + /** + * @param string text for the color picker OK button + */ + public function setOKButtonText($value) + { + $this->setViewState('OKButtonText', $value, 'OK'); + } + + /** + * @return string text for the color picker Cancel button. Default is "Cancel". + */ + public function getCancelButtonText() + { + return $this->getViewState('CancelButtonText', 'Cancel'); + } + + /** + * @param string text for the color picker Cancel button + */ + public function setCancelButtonText($value) + { + $this->setViewState('CancelButtonText', $value, 'Cancel'); + } + + /** + * @return TColorPickerClientSide javascript event options. + */ + public function getClientSide() + { + if($this->_clientSide===null) + $this->_clientSide = $this->createClientSide(); + return $this->_clientSide; + } + + /** + * @return TColorPickerClientSide javascript validator event options. + */ + protected function createClientSide() + { + return new TColorPickerClientSide; + } + + /** + * Get javascript color picker options. + * @return array color picker client-side options + */ + protected function getPostBackOptions() + { + $options = parent::getPostBackOptions(); + $options['ClassName'] = $this->getCssClass(); + $options['ShowColorPicker'] = $this->getShowColorPicker(); + if($options['ShowColorPicker']) + { + $mode = $this->getMode(); + if($mode == TColorPickerMode::Full) $options['Mode'] = $mode; + else if($mode == TColorPickerMode::Simple) $options['Palette'] = 'Tiny'; + $options['OKButtonText'] = $this->getOKButtonText(); + $options['CancelButtonText'] = $this->getCancelButtonText(); + } + $options = array_merge($options,$this->getClientSide()->getOptions()->toArray()); + return $options; + } + + /** + * @param string asset file in the self::SCRIPT_PATH directory. + * @return string asset file url. + */ + protected function getAssetUrl($file='') + { + $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl(); + return $base.'/'.self::SCRIPT_PATH.'/'.$file; + } + + /** + * Publish the color picker Css asset files. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->publishColorPickerAssets(); + } + + /** + * Publish the color picker assets. + */ + protected function publishColorPickerAssets() + { + $cs = $this->getPage()->getClientScript(); + $key = "prado:".get_class($this); + $imgs['button.gif'] = $this->getAssetUrl('button.gif'); + $imgs['background.png'] = $this->getAssetUrl('background.png'); + $options = TJavaScript::encode($imgs); + $code = "Prado.WebUI.TColorPicker.UIImages = {$options};"; + $cs->registerEndScript($key, $code); + $cs->registerPradoScript("colorpicker"); + $url = $this->getAssetUrl($this->getColorPickerStyle().'.css'); + if(!$cs->isStyleSheetFileRegistered($url)) + $cs->registerStyleSheetFile($url, $url); + } + + /** + * Renders additional body content. + * This method overrides parent implementation by adding + * additional color picker button. + * @param THtmlWriter writer + */ + public function renderEndTag($writer) + { + parent::renderEndTag($writer); + + $color = $this->getText(); + $writer->addAttribute('class', 'TColorPicker_button'); + $writer->renderBeginTag('span'); + + $writer->addAttribute('id', $this->getClientID().'_button'); + $writer->addAttribute('src', $this->getAssetUrl('button.gif')); + if($color !== '') + $writer->addAttribute('style', "background-color:{$color};"); + $writer->addAttribute('width', '20'); + $writer->addAttribute('height', '20'); + $writer->addAttribute('alt', ''); + $writer->renderBeginTag('img'); + $writer->renderEndTag(); + $writer->renderEndTag(); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TColorPicker'; + } +} + +/** + * TColorPickerMode class. + * TColorPickerMode defines the enumerable type for the possible UI mode + * that a {@link TColorPicker} control can take. + * + * The following enumerable values are defined: + * # Simple - Grid with 12 simple colors. + * # Basic - Grid with the most common 70 colors. This is the default mode. + * # Full - Full-featured color picker. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TColorPickerMode extends TEnumerable +{ + const Simple='Simple'; + const Basic='Basic'; + const Full='Full'; +} + +/** + * TColorPickerClientSide class. + * + * Client-side javascript code options. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1 + */ +class TColorPickerClientSide extends TClientSideOptions +{ + /** + * @return string javascript code for when a color is selected. + */ + public function getOnColorSelected() + { + return $this->getOption('OnColorSelected'); + } + + /** + * @param string javascript code for when a color is selected. + */ + public function setOnColorSelected($javascript) + { + $this->setFunction('OnColorSelected', $javascript); + } +} + diff --git a/framework/Web/UI/WebControls/TCompareValidator.php b/framework/Web/UI/WebControls/TCompareValidator.php index 57b42018..c936f140 100644 --- a/framework/Web/UI/WebControls/TCompareValidator.php +++ b/framework/Web/UI/WebControls/TCompareValidator.php @@ -1,265 +1,265 @@ -<?php
-/**
- * TCompareValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TCompareValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TCompareValidator class
- *
- * TCompareValidator compares the value entered by the user into an input
- * control with the value entered into another input control or a constant value.
- * To compare the associated input control with another input control,
- * set the {@link setControlToCompare ControlToCompare} property to the ID path
- * of the control to compare with. To compare the associated input control with
- * a constant value, specify the constant value to compare with by setting the
- * {@link setValueToCompare ValueToCompare} property.
- *
- * The {@link setDataType DataType} property is used to specify the data type
- * of both comparison values. Both values are automatically converted to this data
- * type before the comparison operation is performed. The following value types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type. The format can be specified by the
- * {@link setDateFormat DateFormat} property
- * - <b>String</b> A string data type.
- *
- * Use the {@link setOperator Operator} property to specify the type of comparison
- * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
- * LessThan and LessThanEqual.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCompareValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCompareValidator';
- }
-
- /**
- * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType',TValidationDataType::String);
- }
-
- /**
- * Sets the data type that the values being
- * compared are converted to before the comparison is made.
- * @param TValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
- }
-
- /**
- * @return string the input component to compare with the input control being validated.
- */
- public function getControlToCompare()
- {
- return $this->getViewState('ControlToCompare','');
- }
-
- /**
- * Sets the input component to compare with the input control being validated.
- * @param string the ID path of the component to compare with
- */
- public function setControlToCompare($value)
- {
- $this->setViewState('ControlToCompare',$value,'');
- }
-
- /**
- * @return string the constant value to compare with the value entered by the user into the input component being validated.
- */
- public function getValueToCompare()
- {
- return $this->getViewState('ValueToCompare','');
- }
-
- /**
- * Sets the constant value to compare with the value entered by the user into the input component being validated.
- * @param string the constant value
- */
- public function setValueToCompare($value)
- {
- $this->setViewState('ValueToCompare',$value,'');
- }
-
- /**
- * @return TValidationCompareOperator the comparison operation to perform. Defaults to TValidationCompareOperator::Equal.
- */
- public function getOperator()
- {
- return $this->getViewState('Operator',TValidationCompareOperator::Equal);
- }
-
- /**
- * Sets the comparison operation to perform
- * @param TValidationCompareOperator the comparison operation
- */
- public function setOperator($value)
- {
- $this->setViewState('Operator',TPropertyValue::ensureEnum($value,'TValidationCompareOperator'),TValidationCompareOperator::Equal);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data compares successfully.
- * The validation always succeeds if ControlToValidate is not specified
- * or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
-
- if(($controlToCompare=$this->getControlToCompare())!=='')
- {
- if(($control2=$this->findControl($controlToCompare))===null)
- throw new TInvalidDataValueException('comparevalidator_controltocompare_invalid');
- if(($value2=$this->getValidationValue($control2))==='')
- return false;
- }
- else
- $value2=$this->getValueToCompare();
-
- $values = $this->getComparisonValues($value, $value2);
- switch($this->getOperator())
- {
- case TValidationCompareOperator::Equal:
- return $values[0] == $values[1];
- case TValidationCompareOperator::NotEqual:
- return $values[0] != $values[1];
- case TValidationCompareOperator::GreaterThan:
- return $values[0] > $values[1];
- case TValidationCompareOperator::GreaterThanEqual:
- return $values[0] >= $values[1];
- case TValidationCompareOperator::LessThan:
- return $values[0] < $values[1];
- case TValidationCompareOperator::LessThanEqual:
- return $values[0] <= $values[1];
- }
-
- return false;
- }
-
- /**
- * Parse the pair of values into the appropriate value type.
- * @param string value one
- * @param string second value
- * @return array appropriate type of the value pair, array($value1, $value2);
- */
- protected function getComparisonValues($value1, $value2)
- {
- switch($this->getDataType())
- {
- case TValidationDataType::Integer:
- return array(intval($value1), intval($value2));
- case TValidationDataType::Float:
- return array(floatval($value1), floatval($value2));
- case TValidationDataType::Date:
- $dateFormat = $this->getDateFormat();
- if($dateFormat!=='')
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
- return array($formatter->parse($value1), $formatter->parse($value2));
- }
- else
- return array(strtotime($value1), strtotime($value2));
- }
- return array($value1, $value2);
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- if(($name=$this->getControlToCompare())!=='')
- {
- if(($control=$this->findControl($name))!==null)
- $options['ControlToCompare']=$control->getClientID();
- }
- if(($value=$this->getValueToCompare())!=='')
- $options['ValueToCompare']=$value;
- if(($operator=$this->getOperator())!==TValidationCompareOperator::Equal)
- $options['Operator']=$operator;
- $options['DataType']=$this->getDataType();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-}
-
-
-/**
- * TValidationCompareOperator class.
- * TValidationCompareOperator defines the enumerable type for the comparison operations
- * that {@link TCompareValidator} can perform validation with.
- *
- * The following enumerable values are defined:
- * - Equal
- * - NotEqual
- * - GreaterThan
- * - GreaterThanEqual
- * - LessThan
- * - LessThanEqual
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationCompareOperator extends TEnumerable
-{
- const Equal='Equal';
- const NotEqual='NotEqual';
- const GreaterThan='GreaterThan';
- const GreaterThanEqual='GreaterThanEqual';
- const LessThan='LessThan';
- const LessThanEqual='LessThanEqual';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TCompareValidator class + * + * TCompareValidator compares the value entered by the user into an input + * control with the value entered into another input control or a constant value. + * To compare the associated input control with another input control, + * set the {@link setControlToCompare ControlToCompare} property to the ID path + * of the control to compare with. To compare the associated input control with + * a constant value, specify the constant value to compare with by setting the + * {@link setValueToCompare ValueToCompare} property. + * + * The {@link setDataType DataType} property is used to specify the data type + * of both comparison values. Both values are automatically converted to this data + * type before the comparison operation is performed. The following value types are supported: + * - <b>Integer</b> A 32-bit signed integer data type. + * - <b>Float</b> A double-precision floating point number data type. + * - <b>Date</b> A date data type. The format can be specified by the + * {@link setDateFormat DateFormat} property + * - <b>String</b> A string data type. + * + * Use the {@link setOperator Operator} property to specify the type of comparison + * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual, + * LessThan and LessThanEqual. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCompareValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCompareValidator'; + } + + /** + * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String. + */ + public function getDataType() + { + return $this->getViewState('DataType',TValidationDataType::String); + } + + /** + * Sets the data type that the values being + * compared are converted to before the comparison is made. + * @param TValidationDataType the data type + */ + public function setDataType($value) + { + $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String); + } + + /** + * @return string the input component to compare with the input control being validated. + */ + public function getControlToCompare() + { + return $this->getViewState('ControlToCompare',''); + } + + /** + * Sets the input component to compare with the input control being validated. + * @param string the ID path of the component to compare with + */ + public function setControlToCompare($value) + { + $this->setViewState('ControlToCompare',$value,''); + } + + /** + * @return string the constant value to compare with the value entered by the user into the input component being validated. + */ + public function getValueToCompare() + { + return $this->getViewState('ValueToCompare',''); + } + + /** + * Sets the constant value to compare with the value entered by the user into the input component being validated. + * @param string the constant value + */ + public function setValueToCompare($value) + { + $this->setViewState('ValueToCompare',$value,''); + } + + /** + * @return TValidationCompareOperator the comparison operation to perform. Defaults to TValidationCompareOperator::Equal. + */ + public function getOperator() + { + return $this->getViewState('Operator',TValidationCompareOperator::Equal); + } + + /** + * Sets the comparison operation to perform + * @param TValidationCompareOperator the comparison operation + */ + public function setOperator($value) + { + $this->setViewState('Operator',TPropertyValue::ensureEnum($value,'TValidationCompareOperator'),TValidationCompareOperator::Equal); + } + + /** + * Sets the date format for a date validation + * @param string the date format value + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat', $value, ''); + } + + /** + * @return string the date validation date format if any + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat', ''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input data compares successfully. + * The validation always succeeds if ControlToValidate is not specified + * or the input data is empty. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + if(($value=$this->getValidationValue($this->getValidationTarget()))==='') + return true; + + if(($controlToCompare=$this->getControlToCompare())!=='') + { + if(($control2=$this->findControl($controlToCompare))===null) + throw new TInvalidDataValueException('comparevalidator_controltocompare_invalid'); + if(($value2=$this->getValidationValue($control2))==='') + return false; + } + else + $value2=$this->getValueToCompare(); + + $values = $this->getComparisonValues($value, $value2); + switch($this->getOperator()) + { + case TValidationCompareOperator::Equal: + return $values[0] == $values[1]; + case TValidationCompareOperator::NotEqual: + return $values[0] != $values[1]; + case TValidationCompareOperator::GreaterThan: + return $values[0] > $values[1]; + case TValidationCompareOperator::GreaterThanEqual: + return $values[0] >= $values[1]; + case TValidationCompareOperator::LessThan: + return $values[0] < $values[1]; + case TValidationCompareOperator::LessThanEqual: + return $values[0] <= $values[1]; + } + + return false; + } + + /** + * Parse the pair of values into the appropriate value type. + * @param string value one + * @param string second value + * @return array appropriate type of the value pair, array($value1, $value2); + */ + protected function getComparisonValues($value1, $value2) + { + switch($this->getDataType()) + { + case TValidationDataType::Integer: + return array(intval($value1), intval($value2)); + case TValidationDataType::Float: + return array(floatval($value1), floatval($value2)); + case TValidationDataType::Date: + $dateFormat = $this->getDateFormat(); + if($dateFormat!=='') + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat); + return array($formatter->parse($value1), $formatter->parse($value2)); + } + else + return array(strtotime($value1), strtotime($value2)); + } + return array($value1, $value2); + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + if(($name=$this->getControlToCompare())!=='') + { + if(($control=$this->findControl($name))!==null) + $options['ControlToCompare']=$control->getClientID(); + } + if(($value=$this->getValueToCompare())!=='') + $options['ValueToCompare']=$value; + if(($operator=$this->getOperator())!==TValidationCompareOperator::Equal) + $options['Operator']=$operator; + $options['DataType']=$this->getDataType(); + if(($dateFormat=$this->getDateFormat())!=='') + $options['DateFormat']=$dateFormat; + return $options; + } +} + + +/** + * TValidationCompareOperator class. + * TValidationCompareOperator defines the enumerable type for the comparison operations + * that {@link TCompareValidator} can perform validation with. + * + * The following enumerable values are defined: + * - Equal + * - NotEqual + * - GreaterThan + * - GreaterThanEqual + * - LessThan + * - LessThanEqual + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidationCompareOperator extends TEnumerable +{ + const Equal='Equal'; + const NotEqual='NotEqual'; + const GreaterThan='GreaterThan'; + const GreaterThanEqual='GreaterThanEqual'; + const LessThan='LessThan'; + const LessThanEqual='LessThanEqual'; +} + diff --git a/framework/Web/UI/WebControls/TConditional.php b/framework/Web/UI/WebControls/TConditional.php index d04324f0..28af2305 100644 --- a/framework/Web/UI/WebControls/TConditional.php +++ b/framework/Web/UI/WebControls/TConditional.php @@ -1,143 +1,143 @@ -<?php
-/**
- * TConditional class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TConditional class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TConditional class.
- *
- * TConditional displays appropriate content based on the evaluation result
- * of a PHP expression specified via {@link setCondition Condition}.
- * If the result is true, it instantiates the template {@link getTrueTemplate TrueTemplate};
- * otherwise, the template {@link getFalseTemplate FalseTemplate} is instantiated.
- * The PHP expression is evaluated right before {@link onInit} stage of the control lifecycle.
- *
- * Since {@link setCondition Condition} is evaluated at a very early stage, it is recommended
- * you set {@link setCondition Condition} in template and the expression should not refer to
- * objects that are available on or after {@link onInit} lifecycle.
- *
- * A typical usage of TConditional is shown as following:
- * <code>
- * <com:TConditional Condition="$this->User->IsGuest">
- * <prop:TrueTemplate>
- * <a href="path/to/login">Login</a>
- * </prop:TrueTemplate>
- * <prop:FalseTemplate>
- * <a href="path/to/logout">Logout</a>
- * </prop:FalseTemplate>
- * </com:TConditional>
- * </code>
- *
- * TConditional is very light. It instantiates either {@link getTrueTemplate TrueTemplate}
- * or {@link getFalseTemplate FalseTemplate}, but never both. And the condition is evaluated only once.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TConditional extends TControl
-{
- private $_condition='true';
- private $_trueTemplate;
- private $_falseTemplate;
- private $_creatingChildren=false;
-
- /**
- * Processes an object that is created during parsing template.
- * This method overrides the parent implementation by removing
- * all contents enclosed in the template tag.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- if($this->_creatingChildren)
- parent::addParsedObject($object);
- }
-
- /**
- * Creates child controls.
- * This method overrides the parent implementation. It evaluates {@link getCondition Condition}
- * and instantiate the corresponding template.
- */
- public function createChildControls()
- {
- $this->_creatingChildren=true;
- $result=true;
- try
- {
- $result=$this->getTemplateControl()->evaluateExpression($this->_condition);
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('conditional_condition_invalid',$this->_condition,$e->getMessage());
- }
- if($result)
- {
- if($this->_trueTemplate)
- $this->_trueTemplate->instantiateIn($this->getTemplateControl(),$this);
- }
- else if($this->_falseTemplate)
- $this->_falseTemplate->instantiateIn($this->getTemplateControl(),$this);
- $this->_creatingChildren=false;
- }
-
- /**
- * @return string the PHP expression used for determining which template to use. Defaults to 'true', meaning using TrueTemplate.
- */
- public function getCondition()
- {
- return $this->_condition;
- }
-
- /**
- * Sets the PHP expression to be evaluated for conditionally displaying content.
- * The context of the expression is the template control containing TConditional.
- * @param string the PHP expression used for determining which template to use.
- */
- public function setCondition($value)
- {
- $this->_condition=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return ITemplate the template applied when {@link getCondition Condition} is true.
- */
- public function getTrueTemplate()
- {
- return $this->_trueTemplate;
- }
-
- /**
- * @param ITemplate the template applied when {@link getCondition Condition} is true.
- */
- public function setTrueTemplate(ITemplate $value)
- {
- $this->_trueTemplate=$value;
- }
-
- /**
- * @return ITemplate the template applied when {@link getCondition Condition} is false.
- */
- public function getFalseTemplate()
- {
- return $this->_falseTemplate;
- }
-
- /**
- * @param ITemplate the template applied when {@link getCondition Condition} is false.
- */
- public function setFalseTemplate(ITemplate $value)
- {
- $this->_falseTemplate=$value;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TConditional class. + * + * TConditional displays appropriate content based on the evaluation result + * of a PHP expression specified via {@link setCondition Condition}. + * If the result is true, it instantiates the template {@link getTrueTemplate TrueTemplate}; + * otherwise, the template {@link getFalseTemplate FalseTemplate} is instantiated. + * The PHP expression is evaluated right before {@link onInit} stage of the control lifecycle. + * + * Since {@link setCondition Condition} is evaluated at a very early stage, it is recommended + * you set {@link setCondition Condition} in template and the expression should not refer to + * objects that are available on or after {@link onInit} lifecycle. + * + * A typical usage of TConditional is shown as following: + * <code> + * <com:TConditional Condition="$this->User->IsGuest"> + * <prop:TrueTemplate> + * <a href="path/to/login">Login</a> + * </prop:TrueTemplate> + * <prop:FalseTemplate> + * <a href="path/to/logout">Logout</a> + * </prop:FalseTemplate> + * </com:TConditional> + * </code> + * + * TConditional is very light. It instantiates either {@link getTrueTemplate TrueTemplate} + * or {@link getFalseTemplate FalseTemplate}, but never both. And the condition is evaluated only once. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TConditional extends TControl +{ + private $_condition='true'; + private $_trueTemplate; + private $_falseTemplate; + private $_creatingChildren=false; + + /** + * Processes an object that is created during parsing template. + * This method overrides the parent implementation by removing + * all contents enclosed in the template tag. + * @param string|TComponent text string or component parsed and instantiated in template + * @see createdOnTemplate + */ + public function addParsedObject($object) + { + if($this->_creatingChildren) + parent::addParsedObject($object); + } + + /** + * Creates child controls. + * This method overrides the parent implementation. It evaluates {@link getCondition Condition} + * and instantiate the corresponding template. + */ + public function createChildControls() + { + $this->_creatingChildren=true; + $result=true; + try + { + $result=$this->getTemplateControl()->evaluateExpression($this->_condition); + } + catch(Exception $e) + { + throw new TInvalidDataValueException('conditional_condition_invalid',$this->_condition,$e->getMessage()); + } + if($result) + { + if($this->_trueTemplate) + $this->_trueTemplate->instantiateIn($this->getTemplateControl(),$this); + } + else if($this->_falseTemplate) + $this->_falseTemplate->instantiateIn($this->getTemplateControl(),$this); + $this->_creatingChildren=false; + } + + /** + * @return string the PHP expression used for determining which template to use. Defaults to 'true', meaning using TrueTemplate. + */ + public function getCondition() + { + return $this->_condition; + } + + /** + * Sets the PHP expression to be evaluated for conditionally displaying content. + * The context of the expression is the template control containing TConditional. + * @param string the PHP expression used for determining which template to use. + */ + public function setCondition($value) + { + $this->_condition=TPropertyValue::ensureString($value); + } + + /** + * @return ITemplate the template applied when {@link getCondition Condition} is true. + */ + public function getTrueTemplate() + { + return $this->_trueTemplate; + } + + /** + * @param ITemplate the template applied when {@link getCondition Condition} is true. + */ + public function setTrueTemplate(ITemplate $value) + { + $this->_trueTemplate=$value; + } + + /** + * @return ITemplate the template applied when {@link getCondition Condition} is false. + */ + public function getFalseTemplate() + { + return $this->_falseTemplate; + } + + /** + * @param ITemplate the template applied when {@link getCondition Condition} is false. + */ + public function setFalseTemplate(ITemplate $value) + { + $this->_falseTemplate=$value; + } +} + diff --git a/framework/Web/UI/WebControls/TContent.php b/framework/Web/UI/WebControls/TContent.php index 3b17c2cc..60a8e0b6 100644 --- a/framework/Web/UI/WebControls/TContent.php +++ b/framework/Web/UI/WebControls/TContent.php @@ -1,47 +1,47 @@ -<?php
-/**
- * TContent class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TContent class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TContent class
- *
- * TContent specifies a block of content on a control's template
- * that will be injected at somewhere of the master control's template.
- * TContentPlaceHolder and {@link TContent} together implement a decoration
- * pattern for prado templated controls. A template control
- * (called content control) can specify a master control
- * whose template contains some TContentPlaceHolder controls.
- * {@link TContent} controls on the content control's template will replace the corresponding
- * {@link TContentPlaceHolder} controls on the master control's template.
- * This is called content injection. It is done by matching the IDs of
- * {@link TContent} and {@link TContentPlaceHolder} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TContent extends TControl implements INamingContainer
-{
- /**
- * This method is invoked after the control is instantiated on a template.
- * This overrides the parent implementation by registering the content control
- * to the template owner control.
- * @param TControl potential parent of this control
- */
- public function createdOnTemplate($parent)
- {
- if(($id=$this->getID())==='')
- throw new TConfigurationException('content_id_required');
- $this->getTemplateControl()->registerContent($id,$this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TContent class + * + * TContent specifies a block of content on a control's template + * that will be injected at somewhere of the master control's template. + * TContentPlaceHolder and {@link TContent} together implement a decoration + * pattern for prado templated controls. A template control + * (called content control) can specify a master control + * whose template contains some TContentPlaceHolder controls. + * {@link TContent} controls on the content control's template will replace the corresponding + * {@link TContentPlaceHolder} controls on the master control's template. + * This is called content injection. It is done by matching the IDs of + * {@link TContent} and {@link TContentPlaceHolder} controls. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TContent extends TControl implements INamingContainer +{ + /** + * This method is invoked after the control is instantiated on a template. + * This overrides the parent implementation by registering the content control + * to the template owner control. + * @param TControl potential parent of this control + */ + public function createdOnTemplate($parent) + { + if(($id=$this->getID())==='') + throw new TConfigurationException('content_id_required'); + $this->getTemplateControl()->registerContent($id,$this); + } +} + diff --git a/framework/Web/UI/WebControls/TContentPlaceHolder.php b/framework/Web/UI/WebControls/TContentPlaceHolder.php index ddd2b610..55ed461d 100644 --- a/framework/Web/UI/WebControls/TContentPlaceHolder.php +++ b/framework/Web/UI/WebControls/TContentPlaceHolder.php @@ -1,48 +1,48 @@ -<?php
-/**
- * TContentPlaceHolder class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TContentPlaceHolder class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TContentPlaceHolder class
- *
- * TContentPlaceHolder reserves a place on a template where a {@link TContent}
- * control can inject itself and its children in. TContentPlaceHolder and {@link TContent}
- * together implement a decoration pattern for prado templated controls.
- * A template control (called content control) can specify a master control
- * whose template contains some TContentPlaceHolder controls.
- * {@link TContent} controls on the content control's template will replace the corresponding
- * {@link TContentPlaceHolder} controls on the master control's template.
- * This is called content injection. It is done by matching the IDs of
- * {@link TContent} and {@link TContentPlaceHolder} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TContentPlaceHolder extends TControl
-{
- /**
- * This method is invoked after the control is instantiated on a template.
- * This overrides the parent implementation by registering the content placeholder
- * control to the template owner control. The placeholder control will NOT
- * be added to the potential parent control!
- * @param TControl potential parent of this control
- */
- public function createdOnTemplate($parent)
- {
- if(($id=$this->getID())==='')
- throw new TConfigurationException('contentplaceholder_id_required');
- $this->getTemplateControl()->registerContentPlaceHolder($id,$this);
- $parent->getControls()->add($this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TContentPlaceHolder class + * + * TContentPlaceHolder reserves a place on a template where a {@link TContent} + * control can inject itself and its children in. TContentPlaceHolder and {@link TContent} + * together implement a decoration pattern for prado templated controls. + * A template control (called content control) can specify a master control + * whose template contains some TContentPlaceHolder controls. + * {@link TContent} controls on the content control's template will replace the corresponding + * {@link TContentPlaceHolder} controls on the master control's template. + * This is called content injection. It is done by matching the IDs of + * {@link TContent} and {@link TContentPlaceHolder} controls. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TContentPlaceHolder extends TControl +{ + /** + * This method is invoked after the control is instantiated on a template. + * This overrides the parent implementation by registering the content placeholder + * control to the template owner control. The placeholder control will NOT + * be added to the potential parent control! + * @param TControl potential parent of this control + */ + public function createdOnTemplate($parent) + { + if(($id=$this->getID())==='') + throw new TConfigurationException('contentplaceholder_id_required'); + $this->getTemplateControl()->registerContentPlaceHolder($id,$this); + $parent->getControls()->add($this); + } +} + diff --git a/framework/Web/UI/WebControls/TCustomValidator.php b/framework/Web/UI/WebControls/TCustomValidator.php index 9ab75258..dcfadacd 100644 --- a/framework/Web/UI/WebControls/TCustomValidator.php +++ b/framework/Web/UI/WebControls/TCustomValidator.php @@ -1,207 +1,207 @@ -<?php
-/**
- * TCustomValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TCustomValidator class
- *
- * TCustomValidator performs user-defined validation (either
- * server-side or client-side or both) on an input component.
- *
- * To create a server-side validation function, provide a handler for
- * the {@link onServerValidate OnServerValidate} event that performs the validation.
- * The data string of the input control to validate can be accessed
- * by {@link TServerValidateEventParameter::getValue Value} of the event parameter.
- * The result of the validation should be stored in the
- * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event
- * parameter.
- *
- * To create a client-side validation function, add the client-side
- * validation javascript function to the page template.
- * The function should have the following signature:
- * <code>
- * <script type="text/javascript"><!--
- * function ValidationFunctionName(sender, parameter)
- * {
- * // if(parameter == ...)
- * // return true;
- * // else
- * // return false;
- * }
- * --></script>
- * </code>
- * Use the {@link setClientValidationFunction ClientValidationFunction} property
- * to specify the name of the client-side validation script function associated
- * with the TCustomValidator.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCustomValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCustomValidator';
- }
-
- /**
- * @return string the name of the custom client-side script function used for validation.
- */
- public function getClientValidationFunction()
- {
- return $this->getViewState('ClientValidationFunction','');
- }
-
- /**
- * Sets the name of the custom client-side script function used for validation.
- * @param string the script function name
- */
- public function setClientValidationFunction($value)
- {
- $this->setViewState('ClientValidationFunction',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if {@link onServerValidate} returns true.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- $value = '';
- if($this->getValidationTarget()!==null)
- $value=$this->getValidationValue($this->getValidationTarget());
- return $this->onServerValidate($value);
- }
-
- /**
- * This method is invoked when the server side validation happens.
- * It will raise the <b>OnServerValidate</b> event.
- * The method also allows derived classes to handle the event without attaching a delegate.
- * <b>Note</b> The derived classes should call parent implementation
- * to ensure the <b>OnServerValidate</b> event is raised.
- * @param string the value to be validated
- * @return boolean whether the value is valid
- */
- public function onServerValidate($value)
- {
- $param=new TServerValidateEventParameter($value,true);
- $this->raiseEvent('OnServerValidate',$this,$param);
- return $param->getIsValid();
- }
-
- /**
- * @return TControl control to be validated. Null if no control is found.
- */
- public function getValidationTarget()
- {
- if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
- return $control;
- else if(($id=$this->getControlToValidate())!=='')
- throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
- else
- return null;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- if(($clientJs=$this->getClientValidationFunction())!=='')
- $options['ClientValidationFunction']=$clientJs;
- return $options;
- }
-
- /**
- * Only register the client-side validator if
- * {@link setClientValidationFunction ClientValidationFunction} is set.
- */
- protected function registerClientScriptValidator()
- {
- if($this->getClientValidationFunction()!=='')
- parent::registerClientScriptValidator();
- }
-}
-
-/**
- * TServerValidateEventParameter class
- *
- * TServerValidateEventParameter encapsulates the parameter data for
- * <b>OnServerValidate</b> event of TCustomValidator components.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TServerValidateEventParameter extends TEventParameter
-{
- /**
- * the value to be validated
- * @var string
- */
- private $_value='';
- /**
- * whether the value is valid
- * @var boolean
- */
- private $_isValid=true;
-
- /**
- * Constructor.
- * @param string property value to be validated
- * @param boolean whether the value is valid
- */
- public function __construct($value,$isValid)
- {
- $this->_value=$value;
- $this->setIsValid($isValid);
- }
-
- /**
- * @return string value to be validated
- */
- public function getValue()
- {
- return $this->_value;
- }
-
- /**
- * @return boolean whether the value is valid
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the value is valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+<?php +/** + * TCustomValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TCustomValidator class + * + * TCustomValidator performs user-defined validation (either + * server-side or client-side or both) on an input component. + * + * To create a server-side validation function, provide a handler for + * the {@link onServerValidate OnServerValidate} event that performs the validation. + * The data string of the input control to validate can be accessed + * by {@link TServerValidateEventParameter::getValue Value} of the event parameter. + * The result of the validation should be stored in the + * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event + * parameter. + * + * To create a client-side validation function, add the client-side + * validation javascript function to the page template. + * The function should have the following signature: + * <code> + * <script type="text/javascript"><!-- + * function ValidationFunctionName(sender, parameter) + * { + * // if(parameter == ...) + * // return true; + * // else + * // return false; + * } + * --></script> + * </code> + * Use the {@link setClientValidationFunction ClientValidationFunction} property + * to specify the name of the client-side validation script function associated + * with the TCustomValidator. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCustomValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TCustomValidator'; + } + + /** + * @return string the name of the custom client-side script function used for validation. + */ + public function getClientValidationFunction() + { + return $this->getViewState('ClientValidationFunction',''); + } + + /** + * Sets the name of the custom client-side script function used for validation. + * @param string the script function name + */ + public function setClientValidationFunction($value) + { + $this->setViewState('ClientValidationFunction',$value,''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if {@link onServerValidate} returns true. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + $value = ''; + if($this->getValidationTarget()!==null) + $value=$this->getValidationValue($this->getValidationTarget()); + return $this->onServerValidate($value); + } + + /** + * This method is invoked when the server side validation happens. + * It will raise the <b>OnServerValidate</b> event. + * The method also allows derived classes to handle the event without attaching a delegate. + * <b>Note</b> The derived classes should call parent implementation + * to ensure the <b>OnServerValidate</b> event is raised. + * @param string the value to be validated + * @return boolean whether the value is valid + */ + public function onServerValidate($value) + { + $param=new TServerValidateEventParameter($value,true); + $this->raiseEvent('OnServerValidate',$this,$param); + return $param->getIsValid(); + } + + /** + * @return TControl control to be validated. Null if no control is found. + */ + public function getValidationTarget() + { + if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null) + return $control; + else if(($id=$this->getControlToValidate())!=='') + throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this)); + else + return null; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options=parent::getClientScriptOptions(); + if(($clientJs=$this->getClientValidationFunction())!=='') + $options['ClientValidationFunction']=$clientJs; + return $options; + } + + /** + * Only register the client-side validator if + * {@link setClientValidationFunction ClientValidationFunction} is set. + */ + protected function registerClientScriptValidator() + { + if($this->getClientValidationFunction()!=='') + parent::registerClientScriptValidator(); + } +} + +/** + * TServerValidateEventParameter class + * + * TServerValidateEventParameter encapsulates the parameter data for + * <b>OnServerValidate</b> event of TCustomValidator components. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TServerValidateEventParameter extends TEventParameter +{ + /** + * the value to be validated + * @var string + */ + private $_value=''; + /** + * whether the value is valid + * @var boolean + */ + private $_isValid=true; + + /** + * Constructor. + * @param string property value to be validated + * @param boolean whether the value is valid + */ + public function __construct($value,$isValid) + { + $this->_value=$value; + $this->setIsValid($isValid); + } + + /** + * @return string value to be validated + */ + public function getValue() + { + return $this->_value; + } + + /** + * @return boolean whether the value is valid + */ + public function getIsValid() + { + return $this->_isValid; + } + + /** + * @param boolean whether the value is valid + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } +} diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php index 294dd416..076179fb 100644 --- a/framework/Web/UI/WebControls/TDataBoundControl.php +++ b/framework/Web/UI/WebControls/TDataBoundControl.php @@ -1,587 +1,587 @@ -<?php
-/**
- * TDataBoundControl class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataSourceControl');
-Prado::using('System.Web.UI.WebControls.TDataSourceView');
-Prado::using('System.Collections.TPagedDataSource');
-
-/**
- * TDataBoundControl class.
- *
- * TDataBoundControl is the based class for controls that need to populate
- * data from data sources. It provides basic properties and methods that allow
- * the derived controls to associate with data sources and retrieve data from them.
- *
- * TBC....
- *
- * TDataBoundControl is equipped with paging capabilities. By setting
- * {@link setAllowPaging AllowPaging} to true, the input data will be paged
- * and only one page of data is actually populated into the data-bound control.
- * This saves a lot of memory when dealing with larget datasets.
- *
- * To specify the number of data items displayed on each page, set
- * the {@link setPageSize PageSize} property, and to specify which
- * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
- *
- * When the size of the original data is too big to be loaded all in the memory,
- * one can enable custom paging. In custom paging, the total number of data items
- * is specified manually via {@link setVirtualItemCount VirtualItemCount},
- * and the data source only needs to contain the current page of data. To enable
- * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataBoundControl extends TWebControl
-{
- private $_initialized=false;
- private $_dataSource=null;
- private $_requiresBindToNull=false;
- private $_requiresDataBinding=false;
- private $_prerendered=false;
- private $_currentView=null;
- private $_currentDataSource=null;
- private $_currentViewValid=false;
- private $_currentDataSourceValid=false;
- private $_currentViewIsFromDataSourceID=false;
- private $_parameters=null;
- private $_isDataBound=false;
-
- /**
- * @return Traversable data source object, defaults to null.
- */
- public function getDataSource()
- {
- return $this->_dataSource;
- }
-
- /**
- * Sets the data source object associated with the databound control.
- * The data source must implement Traversable interface.
- * If an array is given, it will be converted to xxx.
- * If a string is given, it will be converted to xxx.
- * @param Traversable|array|string data source object
- */
- public function setDataSource($value)
- {
- $this->_dataSource=$this->validateDataSource($value);
- $this->onDataSourceChanged();
- }
-
- /**
- * @return string ID path to the data source control. Defaults to empty.
- */
- public function getDataSourceID()
- {
- return $this->getViewState('DataSourceID','');
- }
-
- /**
- * @param string ID path to the data source control. The data source
- * control must be locatable via {@link TControl::findControl} call.
- */
- public function setDataSourceID($value)
- {
- $dsid=$this->getViewState('DataSourceID','');
- if($dsid!=='' && $value==='')
- $this->_requiresBindToNull=true;
- $this->setViewState('DataSourceID',$value,'');
- $this->onDataSourceChanged();
- }
-
- /**
- * @return boolean if the databound control uses the data source specified
- * by {@link setDataSourceID}, or it uses the data source object specified
- * by {@link setDataSource}.
- */
- protected function getUsingDataSourceID()
- {
- return $this->getDataSourceID()!=='';
- }
-
- /**
- * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
- * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
- */
- public function onDataSourceChanged()
- {
- $this->_currentViewValid=false;
- $this->_currentDataSourceValid=false;
- if($this->getInitialized())
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * @return boolean whether the databound control has been initialized.
- * By default, the control is initialized after its viewstate has been restored.
- */
- protected function getInitialized()
- {
- return $this->_initialized;
- }
-
- /**
- * Sets a value indicating whether the databound control is initialized.
- * If initialized, any modification to {@link setDataSource DataSource} or
- * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
- * as true.
- * @param boolean a value indicating whether the databound control is initialized.
- */
- protected function setInitialized($value)
- {
- $this->_initialized=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether databind has been invoked in the previous page request
- */
- protected function getIsDataBound()
- {
- return $this->_isDataBound;
- }
-
- /**
- * @param boolean if databind has been invoked in this page request
- */
- protected function setIsDataBound($value)
- {
- $this->_isDataBound=$value;
- }
-
- /**
- * @return boolean whether a databind call is required (by the data bound control)
- */
- protected function getRequiresDataBinding()
- {
- return $this->_requiresDataBinding;
- }
-
- /**
- * @return boolean whether paging is enabled. Defaults to false.
- */
- public function getAllowPaging()
- {
- return $this->getViewState('AllowPaging',false);
- }
-
- /**
- * @param boolean whether paging is enabled
- */
- public function setAllowPaging($value)
- {
- $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the custom paging is enabled. Defaults to false.
- */
- public function getAllowCustomPaging()
- {
- return $this->getViewState('AllowCustomPaging',false);
- }
-
- /**
- * Sets a value indicating whether the custom paging should be enabled.
- * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
- * property is used to determine the paging, and the data items in the
- * {@link setDataSource DataSource} are considered to be in the current page.
- * @param boolean whether the custom paging is enabled
- */
- public function setAllowCustomPaging($value)
- {
- $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer the number of data items on each page. Defaults to 10.
- */
- public function getPageSize()
- {
- return $this->getViewState('PageSize',10);
- }
-
- /**
- * @param integer the number of data items on each page.
- * @throws TInvalidDataValueException if the value is less than 1
- */
- public function setPageSize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
- $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
- }
-
- /**
- * @return integer number of pages of data items available
- */
- public function getPageCount()
- {
- return $this->getViewState('PageCount',1);
- }
-
- /**
- * @return integer virtual number of data items in the data source. Defaults to 0.
- * @see setAllowCustomPaging
- */
- public function getVirtualItemCount()
- {
- return $this->getViewState('VirtualItemCount',0);
- }
-
- /**
- * @param integer virtual number of data items in the data source.
- * @throws TInvalidDataValueException if the value is less than 0
- * @see setAllowCustomPaging
- */
- public function setVirtualItemCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
- $this->setViewState('VirtualItemCount',$value,0);
- }
-
- /**
- * Sets a value indicating whether a databind call is required by the data bound control.
- * If true and the control has been prerendered while it uses the data source
- * specified by {@link setDataSourceID}, a databind call will be called by this method.
- * @param boolean whether a databind call is required.
- */
- protected function setRequiresDataBinding($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- if($value && $this->_prerendered)
- {
- $this->_requiresDataBinding=true;
- $this->ensureDataBound();
- }
- else
- $this->_requiresDataBinding=$value;
- }
-
- /**
- * Ensures any pending {@link dataBind} is called.
- * This method calls {@link dataBind} if the data source is specified
- * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
- * is true.
- */
- protected function ensureDataBound()
- {
- if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
- {
- $this->dataBind();
- $this->_requiresBindToNull=false;
- }
- }
-
- /**
- * @return TPagedDataSource creates a paged data source
- */
- protected function createPagedDataSource()
- {
- $ds=new TPagedDataSource;
- $ds->setCurrentPageIndex($this->getCurrentPageIndex());
- $ds->setPageSize($this->getPageSize());
- $ds->setAllowPaging($this->getAllowPaging());
- $ds->setAllowCustomPaging($this->getAllowCustomPaging());
- $ds->setVirtualItemCount($this->getVirtualItemCount());
- return $ds;
- }
-
- /**
- * Performs databinding.
- * This method overrides the parent implementation by calling
- * {@link performSelect} which fetches data from data source and does
- * the actual binding work.
- */
- public function dataBind()
- {
- $this->setRequiresDataBinding(false);
- $this->dataBindProperties();
- $this->onDataBinding(null);
-
- if(($view=$this->getDataSourceView())!==null)
- $data=$view->select($this->getSelectParameters());
- else
- $data=null;
-
- if($data instanceof Traversable)
- {
- if($this->getAllowPaging())
- {
- $ds=$this->createPagedDataSource();
- $ds->setDataSource($data);
- $this->setViewState('PageCount',$ds->getPageCount());
- if($ds->getCurrentPageIndex()>=$ds->getPageCount())
- {
- $ds->setCurrentPageIndex($ds->getPageCount()-1);
- $this->setCurrentPageIndex($ds->getCurrentPageIndex());
- }
- $this->performDataBinding($ds);
- }
- else
- {
- $this->clearViewState('PageCount');
- $this->performDataBinding($data);
- }
- }
- $this->setIsDataBound(true);
- $this->onDataBound(null);
- }
-
- public function dataSourceViewChanged($sender,$param)
- {
- if(!$this->_ignoreDataSourceViewChanged)
- $this->setRequiresDataBinding(true);
- }
-
- protected function getDataSourceView()
- {
- if(!$this->_currentViewValid)
- {
- if($this->_currentView && $this->_currentViewIsFromDataSourceID)
- $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
- if(($dataSource=$this->determineDataSource())!==null)
- {
- if(($view=$dataSource->getView($this->getDataMember()))===null)
- throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
- if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
- $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
- $this->_currentView=$view;
- }
- else
- $this->_currentView=null;
- $this->_currentViewValid=true;
- }
- return $this->_currentView;
- }
-
- protected function determineDataSource()
- {
- if(!$this->_currentDataSourceValid)
- {
- if(($dsid=$this->getDataSourceID())!=='')
- {
- if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
- else if(!($dataSource instanceof IDataSource))
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
- else
- $this->_currentDataSource=$dataSource;
- }
- else if(($dataSource=$this->getDataSource())!==null)
- $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
- else
- $this->_currentDataSource=null;
- $this->_currentDataSourceValid=true;
- }
- return $this->_currentDataSource;
- }
-
- abstract protected function performDataBinding($data);
-
- /**
- * Raises <b>OnDataBound</b> event.
- * This method should be invoked after a databind is performed.
- * It is mainly used by framework and component developers.
- */
- public function onDataBound($param)
- {
- $this->raiseEvent('OnDataBound',$this,$param);
- }
-
- /**
- * Sets page's <b>OnPreLoad</b> event handler as {@link pagePreLoad}.
- * If viewstate is disabled and the current request is a postback,
- * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $page=$this->getPage();
- $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
- }
-
- /**
- * Sets {@link getInitialized} as true.
- * This method is invoked when page raises <b>PreLoad</b> event.
- * @param mixed event sender
- * @param TEventParameter event parameter
- */
- public function pagePreLoad($sender,$param)
- {
- $this->_initialized=true;
- $isPostBack=$this->getPage()->getIsPostBack();
- if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * Ensures any pending databind is performed.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onPreRender($param)
- {
- $this->_prerendered=true;
- $this->ensureDataBound();
- parent::onPreRender($param);
- }
-
- /**
- * Validates if the parameter is a valid data source.
- * If it is a string or an array, it will be converted as a TList object.
- * @param Traversable|array|string data source to be validated
- * @return Traversable the data that is traversable
- * @throws TInvalidDataTypeException if the data is neither null nor Traversable
- */
- protected function validateDataSource($value)
- {
- if(is_string($value))
- {
- $list=new TList;
- foreach(TPropertyValue::ensureArray($value) as $key=>$value)
- {
- if(is_array($value))
- $list->add($value);
- else
- $list->add(array($value,is_string($key)?$key:$value));
- }
- return $list;
- }
- else if(is_array($value))
- return new TMap($value);
- else if($value instanceof TDbDataReader) {
- // read array from TDbDataReader since it's forward-only stream and can only be traversed once
- return $value->readAll();
- }
- else if(($value instanceof Traversable) || $value===null)
- return $value;
- else
- throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
- }
-
- public function getDataMember()
- {
- return $this->getViewState('DataMember','');
- }
-
- public function setDataMember($value)
- {
- $this->setViewState('DataMember',$value,'');
- }
-
- public function getSelectParameters()
- {
- if(!$this->_parameters)
- $this->_parameters=new TDataSourceSelectParameters;
- return $this->_parameters;
- }
-}
-
-
-/**
- * TListItemType class.
- * TListItemType defines the enumerable type for the possible types
- * that databound list items could take.
- *
- * The following enumerable values are defined:
- * - Header: header item
- * - Footer: footer item
- * - Item: content item (neither header nor footer)
- * - Separator: separator between items
- * - AlternatingItem: alternating content item
- * - EditItem: content item in edit mode
- * - SelectedItem: selected content item
- * - Pager: pager
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TListItemType extends TEnumerable
-{
- const Header='Header';
- const Footer='Footer';
- const Item='Item';
- const Separator='Separator';
- const AlternatingItem='AlternatingItem';
- const EditItem='EditItem';
- const SelectedItem='SelectedItem';
- const Pager='Pager';
-}
-
-
-/**
- * IItemDataRenderer interface.
- *
- * IItemDataRenderer defines the interface that an item renderer
- * needs to implement. Besides the {@link getData Data} property, a list item
- * renderer also needs to provide {@link getItemIndex ItemIndex} and
- * {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-interface IItemDataRenderer extends IDataRenderer
-{
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex();
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value);
-
- /**
- * @return TListItemType the item type.
- */
- public function getItemType();
-
- /**
- * @param TListItemType the item type.
- */
- public function setItemType($value);
-}
-
-?>
+<?php +/** + * TDataBoundControl class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataSourceControl'); +Prado::using('System.Web.UI.WebControls.TDataSourceView'); +Prado::using('System.Collections.TPagedDataSource'); + +/** + * TDataBoundControl class. + * + * TDataBoundControl is the based class for controls that need to populate + * data from data sources. It provides basic properties and methods that allow + * the derived controls to associate with data sources and retrieve data from them. + * + * TBC.... + * + * TDataBoundControl is equipped with paging capabilities. By setting + * {@link setAllowPaging AllowPaging} to true, the input data will be paged + * and only one page of data is actually populated into the data-bound control. + * This saves a lot of memory when dealing with larget datasets. + * + * To specify the number of data items displayed on each page, set + * the {@link setPageSize PageSize} property, and to specify which + * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}. + * + * When the size of the original data is too big to be loaded all in the memory, + * one can enable custom paging. In custom paging, the total number of data items + * is specified manually via {@link setVirtualItemCount VirtualItemCount}, + * and the data source only needs to contain the current page of data. To enable + * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataBoundControl extends TWebControl +{ + private $_initialized=false; + private $_dataSource=null; + private $_requiresBindToNull=false; + private $_requiresDataBinding=false; + private $_prerendered=false; + private $_currentView=null; + private $_currentDataSource=null; + private $_currentViewValid=false; + private $_currentDataSourceValid=false; + private $_currentViewIsFromDataSourceID=false; + private $_parameters=null; + private $_isDataBound=false; + + /** + * @return Traversable data source object, defaults to null. + */ + public function getDataSource() + { + return $this->_dataSource; + } + + /** + * Sets the data source object associated with the databound control. + * The data source must implement Traversable interface. + * If an array is given, it will be converted to xxx. + * If a string is given, it will be converted to xxx. + * @param Traversable|array|string data source object + */ + public function setDataSource($value) + { + $this->_dataSource=$this->validateDataSource($value); + $this->onDataSourceChanged(); + } + + /** + * @return string ID path to the data source control. Defaults to empty. + */ + public function getDataSourceID() + { + return $this->getViewState('DataSourceID',''); + } + + /** + * @param string ID path to the data source control. The data source + * control must be locatable via {@link TControl::findControl} call. + */ + public function setDataSourceID($value) + { + $dsid=$this->getViewState('DataSourceID',''); + if($dsid!=='' && $value==='') + $this->_requiresBindToNull=true; + $this->setViewState('DataSourceID',$value,''); + $this->onDataSourceChanged(); + } + + /** + * @return boolean if the databound control uses the data source specified + * by {@link setDataSourceID}, or it uses the data source object specified + * by {@link setDataSource}. + */ + protected function getUsingDataSourceID() + { + return $this->getDataSourceID()!==''; + } + + /** + * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized. + * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed. + */ + public function onDataSourceChanged() + { + $this->_currentViewValid=false; + $this->_currentDataSourceValid=false; + if($this->getInitialized()) + $this->setRequiresDataBinding(true); + } + + /** + * @return boolean whether the databound control has been initialized. + * By default, the control is initialized after its viewstate has been restored. + */ + protected function getInitialized() + { + return $this->_initialized; + } + + /** + * Sets a value indicating whether the databound control is initialized. + * If initialized, any modification to {@link setDataSource DataSource} or + * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding} + * as true. + * @param boolean a value indicating whether the databound control is initialized. + */ + protected function setInitialized($value) + { + $this->_initialized=TPropertyValue::ensureBoolean($value); + } + + /** + * @return boolean whether databind has been invoked in the previous page request + */ + protected function getIsDataBound() + { + return $this->_isDataBound; + } + + /** + * @param boolean if databind has been invoked in this page request + */ + protected function setIsDataBound($value) + { + $this->_isDataBound=$value; + } + + /** + * @return boolean whether a databind call is required (by the data bound control) + */ + protected function getRequiresDataBinding() + { + return $this->_requiresDataBinding; + } + + /** + * @return boolean whether paging is enabled. Defaults to false. + */ + public function getAllowPaging() + { + return $this->getViewState('AllowPaging',false); + } + + /** + * @param boolean whether paging is enabled + */ + public function setAllowPaging($value) + { + $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether the custom paging is enabled. Defaults to false. + */ + public function getAllowCustomPaging() + { + return $this->getViewState('AllowCustomPaging',false); + } + + /** + * Sets a value indicating whether the custom paging should be enabled. + * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount} + * property is used to determine the paging, and the data items in the + * {@link setDataSource DataSource} are considered to be in the current page. + * @param boolean whether the custom paging is enabled + */ + public function setAllowCustomPaging($value) + { + $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return integer the zero-based index of the current page. Defaults to 0. + */ + public function getCurrentPageIndex() + { + return $this->getViewState('CurrentPageIndex',0); + } + + /** + * @param integer the zero-based index of the current page + * @throws TInvalidDataValueException if the value is less than 0 + */ + public function setCurrentPageIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->setViewState('CurrentPageIndex',$value,0); + } + + /** + * @return integer the number of data items on each page. Defaults to 10. + */ + public function getPageSize() + { + return $this->getViewState('PageSize',10); + } + + /** + * @param integer the number of data items on each page. + * @throws TInvalidDataValueException if the value is less than 1 + */ + public function setPageSize($value) + { + if(($value=TPropertyValue::ensureInteger($value))<1) + throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this)); + $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10); + } + + /** + * @return integer number of pages of data items available + */ + public function getPageCount() + { + return $this->getViewState('PageCount',1); + } + + /** + * @return integer virtual number of data items in the data source. Defaults to 0. + * @see setAllowCustomPaging + */ + public function getVirtualItemCount() + { + return $this->getViewState('VirtualItemCount',0); + } + + /** + * @param integer virtual number of data items in the data source. + * @throws TInvalidDataValueException if the value is less than 0 + * @see setAllowCustomPaging + */ + public function setVirtualItemCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this)); + $this->setViewState('VirtualItemCount',$value,0); + } + + /** + * Sets a value indicating whether a databind call is required by the data bound control. + * If true and the control has been prerendered while it uses the data source + * specified by {@link setDataSourceID}, a databind call will be called by this method. + * @param boolean whether a databind call is required. + */ + protected function setRequiresDataBinding($value) + { + $value=TPropertyValue::ensureBoolean($value); + if($value && $this->_prerendered) + { + $this->_requiresDataBinding=true; + $this->ensureDataBound(); + } + else + $this->_requiresDataBinding=$value; + } + + /** + * Ensures any pending {@link dataBind} is called. + * This method calls {@link dataBind} if the data source is specified + * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding} + * is true. + */ + protected function ensureDataBound() + { + if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull)) + { + $this->dataBind(); + $this->_requiresBindToNull=false; + } + } + + /** + * @return TPagedDataSource creates a paged data source + */ + protected function createPagedDataSource() + { + $ds=new TPagedDataSource; + $ds->setCurrentPageIndex($this->getCurrentPageIndex()); + $ds->setPageSize($this->getPageSize()); + $ds->setAllowPaging($this->getAllowPaging()); + $ds->setAllowCustomPaging($this->getAllowCustomPaging()); + $ds->setVirtualItemCount($this->getVirtualItemCount()); + return $ds; + } + + /** + * Performs databinding. + * This method overrides the parent implementation by calling + * {@link performSelect} which fetches data from data source and does + * the actual binding work. + */ + public function dataBind() + { + $this->setRequiresDataBinding(false); + $this->dataBindProperties(); + $this->onDataBinding(null); + + if(($view=$this->getDataSourceView())!==null) + $data=$view->select($this->getSelectParameters()); + else + $data=null; + + if($data instanceof Traversable) + { + if($this->getAllowPaging()) + { + $ds=$this->createPagedDataSource(); + $ds->setDataSource($data); + $this->setViewState('PageCount',$ds->getPageCount()); + if($ds->getCurrentPageIndex()>=$ds->getPageCount()) + { + $ds->setCurrentPageIndex($ds->getPageCount()-1); + $this->setCurrentPageIndex($ds->getCurrentPageIndex()); + } + $this->performDataBinding($ds); + } + else + { + $this->clearViewState('PageCount'); + $this->performDataBinding($data); + } + } + $this->setIsDataBound(true); + $this->onDataBound(null); + } + + public function dataSourceViewChanged($sender,$param) + { + if(!$this->_ignoreDataSourceViewChanged) + $this->setRequiresDataBinding(true); + } + + protected function getDataSourceView() + { + if(!$this->_currentViewValid) + { + if($this->_currentView && $this->_currentViewIsFromDataSourceID) + $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged')); + if(($dataSource=$this->determineDataSource())!==null) + { + if(($view=$dataSource->getView($this->getDataMember()))===null) + throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember()); + if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID()) + $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged')); + $this->_currentView=$view; + } + else + $this->_currentView=null; + $this->_currentViewValid=true; + } + return $this->_currentView; + } + + protected function determineDataSource() + { + if(!$this->_currentDataSourceValid) + { + if(($dsid=$this->getDataSourceID())!=='') + { + if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null) + throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid); + else if(!($dataSource instanceof IDataSource)) + throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid); + else + $this->_currentDataSource=$dataSource; + } + else if(($dataSource=$this->getDataSource())!==null) + $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember()); + else + $this->_currentDataSource=null; + $this->_currentDataSourceValid=true; + } + return $this->_currentDataSource; + } + + abstract protected function performDataBinding($data); + + /** + * Raises <b>OnDataBound</b> event. + * This method should be invoked after a databind is performed. + * It is mainly used by framework and component developers. + */ + public function onDataBound($param) + { + $this->raiseEvent('OnDataBound',$this,$param); + } + + /** + * Sets page's <b>OnPreLoad</b> event handler as {@link pagePreLoad}. + * If viewstate is disabled and the current request is a postback, + * {@link setRequiresDataBinding RequiresDataBinding} will be set true. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $page=$this->getPage(); + $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad')); + } + + /** + * Sets {@link getInitialized} as true. + * This method is invoked when page raises <b>PreLoad</b> event. + * @param mixed event sender + * @param TEventParameter event parameter + */ + public function pagePreLoad($sender,$param) + { + $this->_initialized=true; + $isPostBack=$this->getPage()->getIsPostBack(); + if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound()))) + $this->setRequiresDataBinding(true); + } + + /** + * Ensures any pending databind is performed. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onPreRender($param) + { + $this->_prerendered=true; + $this->ensureDataBound(); + parent::onPreRender($param); + } + + /** + * Validates if the parameter is a valid data source. + * If it is a string or an array, it will be converted as a TList object. + * @param Traversable|array|string data source to be validated + * @return Traversable the data that is traversable + * @throws TInvalidDataTypeException if the data is neither null nor Traversable + */ + protected function validateDataSource($value) + { + if(is_string($value)) + { + $list=new TList; + foreach(TPropertyValue::ensureArray($value) as $key=>$value) + { + if(is_array($value)) + $list->add($value); + else + $list->add(array($value,is_string($key)?$key:$value)); + } + return $list; + } + else if(is_array($value)) + return new TMap($value); + else if($value instanceof TDbDataReader) { + // read array from TDbDataReader since it's forward-only stream and can only be traversed once + return $value->readAll(); + } + else if(($value instanceof Traversable) || $value===null) + return $value; + else + throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this)); + } + + public function getDataMember() + { + return $this->getViewState('DataMember',''); + } + + public function setDataMember($value) + { + $this->setViewState('DataMember',$value,''); + } + + public function getSelectParameters() + { + if(!$this->_parameters) + $this->_parameters=new TDataSourceSelectParameters; + return $this->_parameters; + } +} + + +/** + * TListItemType class. + * TListItemType defines the enumerable type for the possible types + * that databound list items could take. + * + * The following enumerable values are defined: + * - Header: header item + * - Footer: footer item + * - Item: content item (neither header nor footer) + * - Separator: separator between items + * - AlternatingItem: alternating content item + * - EditItem: content item in edit mode + * - SelectedItem: selected content item + * - Pager: pager + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TListItemType extends TEnumerable +{ + const Header='Header'; + const Footer='Footer'; + const Item='Item'; + const Separator='Separator'; + const AlternatingItem='AlternatingItem'; + const EditItem='EditItem'; + const SelectedItem='SelectedItem'; + const Pager='Pager'; +} + + +/** + * IItemDataRenderer interface. + * + * IItemDataRenderer defines the interface that an item renderer + * needs to implement. Besides the {@link getData Data} property, a list item + * renderer also needs to provide {@link getItemIndex ItemIndex} and + * {@link getItemType ItemType} property. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +interface IItemDataRenderer extends IDataRenderer +{ + /** + * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection. + * If the item is not in the collection (e.g. it is a header item), it returns -1. + * @return integer zero-based index of the item. + */ + public function getItemIndex(); + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value); + + /** + * @return TListItemType the item type. + */ + public function getItemType(); + + /** + * @param TListItemType the item type. + */ + public function setItemType($value); +} + +?> diff --git a/framework/Web/UI/WebControls/TDataGrid.php b/framework/Web/UI/WebControls/TDataGrid.php index 2af66b33..2e2c5252 100644 --- a/framework/Web/UI/WebControls/TDataGrid.php +++ b/framework/Web/UI/WebControls/TDataGrid.php @@ -1,2258 +1,2258 @@ -<?php
-/**
- * TDataGrid related class files.
- * This file contains the definition of the following classes:
- * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection,
- * TDataGridPagerStyle, TDataGridItemEventParameter,
- * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter,
- * TDataGridPageChangedEventParameter
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-Prado::using('System.Collections.TPagedDataSource');
-Prado::using('System.Collections.TDummyDataSource');
-Prado::using('System.Web.UI.WebControls.TTable');
-Prado::using('System.Web.UI.WebControls.TPanel');
-Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
-
-/**
- * TDataGrid class
- *
- * TDataGrid represents a data bound and updatable grid control.
- *
- * To populate data into the datagrid, sets its {@link setDataSource DataSource}
- * to a tabular data source and call {@link dataBind()}.
- * Each row of data will be represented by an item in the {@link getItems Items}
- * collection of the datagrid.
- *
- * An item can be at one of three states: browsing, selected and edit.
- * The state determines how the item will be displayed. For example, if an item
- * is in edit state, it may be displayed as a table row with input text boxes
- * if the columns are of type {@link TBoundColumn}; and if in browsing state,
- * they are displayed as static text.
- *
- * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
- * or {@link setSelectedItemIndex SelectedItemIndex} property.
- *
- * Each datagrid item has a {@link TDataGridItem::getItemType type}
- * which tells the position and state of the item in the datalist. An item in the header
- * of the repeater is of type Header. A body item may be of either
- * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
- * index is odd or even, whether it is being selected or edited.
- *
- * A datagrid is specified with a list of columns. Each column specifies how the corresponding
- * table column will be displayed. For example, the header/footer text of that column,
- * the cells in that column, and so on. The following column types are currently
- * provided by the framework,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * There are three ways to specify columns for a datagrid.
- * <ul>
- * <li>Automatically generated based on data source.
- * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
- * a list of columns will be automatically generated based on the schema of the data source.
- * Each column corresponds to a column of the data.</li>
- * <li>Specified in template. For example,
- * <code>
- * <com:TDataGrid ...>
- * <com:TBoundColumn .../>
- * <com:TEditCommandColumn .../>
- * </com:TDataGrid>
- * </code>
- * </li>
- * <li>Manually created in code. Columns can be manipulated via
- * the {@link setColumns Columns} property of the datagrid. For example,
- * <code>
- * $column=new TBoundColumn;
- * $datagrid->Columns[]=$column;
- * </code>
- * </li>
- * </ul>
- * Note, automatically generated columns cannot be accessed via
- * the {@link getColumns Columns} property.
- *
- * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
- * is set to true, a column with nonempty {@link setSortExpression SortExpression}
- * will have its header text displayed as a clickable link button.
- * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
- * event. You can respond to this event, sort the data source according
- * to the event parameter, and then invoke {@link databind()} on the datagrid
- * to show to end users the sorted data.
- *
- * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
- * is set to true, a pager will be displayed on top and/or bottom of the table.
- * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
- * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
- * event. You can respond to this event, specify the page to be displayed by
- * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property,
- * and then invoke {@link databind()} on the datagrid to show to end users
- * a new page of data.
- *
- * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
- * datasource. The number of pages {@link getPageCount PageCount} is calculated based
- * the item number and the {@link setPageSize PageSize} property.
- * The datagrid will manage which section of the data source to be displayed
- * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
- * The second approach calculates the page number based on the
- * {@link setVirtualItemCount VirtualItemCount} property and
- * the {@link setPageSize PageSize} property. The datagrid will always
- * display from the beginning of the datasource up to the number of
- * {@link setPageSize PageSize} data items. This approach is especially
- * useful when the datasource may contain too many data items to be managed by
- * the datagrid efficiently.
- *
- * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
- * event, the event will be bubbled up to the datagrid control.
- * If the event's command name is recognizable by the datagrid control,
- * a corresponding item event will be raised. The following item events will be
- * raised upon a specific command:
- * - OnEditCommand, if CommandName=edit
- * - OnCancelCommand, if CommandName=cancel
- * - OnSelectCommand, if CommandName=select
- * - OnDeleteCommand, if CommandName=delete
- * - OnUpdateCommand, if CommandName=update
- * - onPageIndexChanged, if CommandName=page
- * - OnSortCommand, if CommandName=sort
- * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
- * the above specific command events.
- *
- * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
- * every newly created datagrid item. You can respond to this event to customize
- * the content or style of the newly created item.
- *
- * Note, the data bound to the datagrid are reset to null after databinding.
- * There are several ways to access the data associated with a datagrid row:
- * - Access the data in {@link onItemDataBound OnItemDataBound} event
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datagrid row and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the data in viewstate and get it back during postbacks.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGrid extends TBaseDataList implements INamingContainer
-{
- /**
- * datagrid item types
- * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
- */
- const IT_HEADER='Header';
- const IT_FOOTER='Footer';
- const IT_ITEM='Item';
- const IT_SEPARATOR='Separator';
- const IT_ALTERNATINGITEM='AlternatingItem';
- const IT_EDITITEM='EditItem';
- const IT_SELECTEDITEM='SelectedItem';
- const IT_PAGER='Pager';
-
- /**
- * Command name that TDataGrid understands.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
- const CMD_SORT='Sort';
- const CMD_PAGE='Page';
- const CMD_PAGE_NEXT='Next';
- const CMD_PAGE_PREV='Previous';
- const CMD_PAGE_FIRST='First';
- const CMD_PAGE_LAST='Last';
-
- /**
- * @var TDataGridColumnCollection manually created column collection
- */
- private $_columns=null;
- /**
- * @var TDataGridColumnCollection automatically created column collection
- */
- private $_autoColumns=null;
- /**
- * @var TList all columns including both manually and automatically created columns
- */
- private $_allColumns=null;
- /**
- * @var TDataGridItemCollection datagrid item collection
- */
- private $_items=null;
- /**
- * @var TDataGridItem header item
- */
- private $_header=null;
- /**
- * @var TDataGridItem footer item
- */
- private $_footer=null;
- /**
- * @var TPagedDataSource paged data source object
- */
- private $_pagedDataSource=null;
- private $_topPager=null;
- private $_bottomPager=null;
- /**
- * @var ITemplate template used when empty data is bounded
- */
- private $_emptyTemplate=null;
- /**
- * @var boolean whether empty template is effective
- */
- private $_useEmptyTemplate=false;
-
- /**
- * @return string tag name (table) of the datagrid
- */
- protected function getTagName()
- {
- return 'table';
- }
-
- /**
- * @return string Name of the class used in AutoGenerateColumns mode
- */
- protected function getAutoGenerateColumnName()
- {
- return 'TBoundColumn';
- }
-
- /**
- * Adds objects parsed in template to datagrid.
- * Datagrid columns are added into {@link getColumns Columns} collection.
- * @param mixed object parsed in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TDataGridColumn)
- $this->getColumns()->add($object);
- else
- parent::addParsedObject($object); // this is needed by EmptyTemplate
- }
-
- /**
- * @return TDataGridColumnCollection manually specified datagrid columns
- */
- public function getColumns()
- {
- if(!$this->_columns)
- $this->_columns=new TDataGridColumnCollection($this);
- return $this->_columns;
- }
-
- /**
- * @return TDataGridColumnCollection automatically generated datagrid columns
- */
- public function getAutoColumns()
- {
- if(!$this->_autoColumns)
- $this->_autoColumns=new TDataGridColumnCollection($this);
- return $this->_autoColumns;
- }
-
- /**
- * @return TDataGridItemCollection datagrid item collection
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataGridItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by datagrid.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return string the URL of the background image for the datagrid
- */
- public function getBackImageUrl()
- {
- return $this->getStyle()->getBackImageUrl();
- }
-
- /**
- * @param string the URL of the background image for the datagrid
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * @return TTableItemStyle the style for every item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TDataGridPagerStyle the style for pager
- */
- public function getPagerStyle()
- {
- if(($style=$this->getViewState('PagerStyle',null))===null)
- {
- $style=new TDataGridPagerStyle;
- $this->setViewState('PagerStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for thead element, if any
- * @since 3.1.1
- */
- public function getTableHeadStyle()
- {
- if(($style=$this->getViewState('TableHeadStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableHeadStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tbody element, if any
- * @since 3.1.1
- */
- public function getTableBodyStyle()
- {
- if(($style=$this->getViewState('TableBodyStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableBodyStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tfoot element, if any
- * @since 3.1.1
- */
- public function getTableFootStyle()
- {
- if(($style=$this->getViewState('TableFootStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableFootStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string caption for the datagrid
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string caption for the datagrid
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',$value,'');
- }
-
- /**
- * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
- }
-
- /**
- * @param TTableCaptionAlign datagrid caption alignment. Valid values include
- */
- public function setCaptionAlign($value)
- {
- $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
- }
-
- /**
- * @return TDataGridItem the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TDataGridItem the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
- */
- public function getTopPager()
- {
- return $this->_topPager;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
- */
- public function getBottomPager()
- {
- return $this->_bottomPager;
- }
-
- /**
- * @return TDataGridItem the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TDataGridItem the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return boolean whether sorting is enabled. Defaults to false.
- */
- public function getAllowSorting()
- {
- return $this->getViewState('AllowSorting',false);
- }
-
- /**
- * @param boolean whether sorting is enabled
- */
- public function setAllowSorting($value)
- {
- $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
- */
- public function getAutoGenerateColumns()
- {
- return $this->getViewState('AutoGenerateColumns',true);
- }
-
- /**
- * @param boolean whether datagrid columns should be automatically generated
- */
- public function setAutoGenerateColumns($value)
- {
- $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the header should be displayed. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether the header should be displayed
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be displayed. Defaults to false.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',false);
- }
-
- /**
- * @param boolean whether the footer should be displayed
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datagrid
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datagrid
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * {@link TDataGridItem} child controls.
- * If the event parameter is {@link TDataGridCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataGridCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- $this->setSelectedItemIndex($param->getItem()->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_SORT)===0)
- {
- $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE)===0)
- {
- $p=$param->getCommandParameter();
- if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
- $pageIndex=$this->getCurrentPageIndex()+1;
- else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
- $pageIndex=$this->getCurrentPageIndex()-1;
- else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
- $pageIndex=0;
- else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
- $pageIndex=$this->getPageCount()-1;
- else
- $pageIndex=TPropertyValue::ensureInteger($p)-1;
- $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Raises <b>OnCancelCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>cancel</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnDeleteCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>delete</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnEditCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>edit</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnSortCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>sort</b> command name.
- * @param TDataGridSortCommandEventParameter event parameter
- */
- public function onSortCommand($param)
- {
- $this->raiseEvent('OnSortCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnUpdateCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>update</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked right after a datagrid item is created and before
- * added to page hierarchy.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnPagerCreated</b> event.
- * This method is invoked right after a datagrid pager is created and before
- * added to page hierarchy.
- * @param TDataGridPagerEventParameter event parameter
- */
- public function onPagerCreated($param)
- {
- $this->raiseEvent('OnPagerCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked for each datagrid item after it performs
- * databinding.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnPageIndexChanged</b> event.
- * This method is invoked when current page is changed.
- * @param TDataGridPageChangedEventParameter event parameter
- */
- public function onPageIndexChanged($param)
- {
- $this->raiseEvent('OnPageIndexChanged',$this,$param);
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if(!$this->getEnableViewState(true))
- return;
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- if($this->_autoColumns)
- {
- $state=array();
- foreach($this->_autoColumns as $column)
- $state[]=$column->saveState();
- $this->setViewState('AutoColumns',$state,array());
- }
- else
- $this->clearViewState('AutoColumns');
- if($this->_columns)
- {
- $state=array();
- foreach($this->_columns as $column)
- $state[]=$column->saveState();
- $this->setViewState('Columns',$state,array());
- }
- else
- $this->clearViewState('Columns');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getEnableViewState(true))
- return;
- if(!$this->getIsDataBound())
- {
- $state=$this->getViewState('AutoColumns',array());
- if(!empty($state))
- {
- $this->_autoColumns=new TDataGridColumnCollection($this);
- foreach($state as $st)
- {
- $column=new $this->AutoGenerateColumnName;
- $column->loadState($st);
- $this->_autoColumns->add($column);
- }
- }
- else
- $this->_autoColumns=null;
- $state=$this->getViewState('Columns',array());
- if($this->_columns && $this->_columns->getCount()===count($state))
- {
- $i=0;
- foreach($this->_columns as $column)
- {
- $column->loadState($state[$i]);
- $i++;
- }
- }
- $this->restoreGridFromViewState();
- }
- }
-
- /**
- * Clears up all items in the datagrid.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- $this->_topPager=null;
- $this->_bottomPager=null;
- $this->_useEmptyTemplate=false;
- }
-
- /**
- * Restores datagrid content from viewstate.
- */
- protected function restoreGridFromViewState()
- {
- $this->reset();
-
- $allowPaging=$this->getAllowPaging();
-
- $itemCount=$this->getViewState('ItemCount',0);
- $dsIndex=$this->getViewState('DataSourceIndex',0);
-
- $columns=new TList($this->getColumns());
- $columns->mergeWith($this->_autoColumns);
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- for($index=0;$index<$itemCount;++$index)
- {
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- }
- }
-
- /**
- * Performs databinding to populate datagrid items from data source.
- * This method is invoked by {@link dataBind()}.
- * You may override this function to provide your own way of data population.
- * @param Traversable the bound data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
-
- // get all columns
- if($this->getAutoGenerateColumns())
- {
- $columns=new TList($this->getColumns());
- $autoColumns=$this->createAutoColumns($data);
- $columns->mergeWith($autoColumns);
- }
- else
- $columns=$this->getColumns();
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- $index=0;
- $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
- $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
- $this->setViewState('DataSourceIndex',$dsIndex,0);
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$row)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($row,$keyField));
- else
- $keys->add($key);
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
- $index++;
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- $this->setViewState('ItemCount',$index,0);
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- $this->dataBindChildren();
- }
- }
-
- /**
- * Merges consecutive cells who have the same text.
- * @since 3.1.1
- */
- private function groupCells()
- {
- if(($columns=$this->_allColumns)===null)
- return;
- $items=$this->getItems();
- foreach($columns as $id=>$column)
- {
- if(!$column->getEnableCellGrouping())
- continue;
- $prevCell=null;
- $prevCellText=null;
- foreach($items as $item)
- {
- $itemType=$item->getItemType();
- $cell=$item->getCells()->itemAt($id);
- if(!$cell->getVisible())
- continue;
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- if(($cellText=$this->getCellText($cell))==='')
- {
- $prevCell=null;
- $prevCellText=null;
- continue;
- }
- if($prevCell===null || $prevCellText!==$cellText)
- {
- $prevCell=$cell;
- $prevCellText=$cellText;
- }
- else
- {
- if(($rowSpan=$prevCell->getRowSpan())===0)
- $rowSpan=1;
- $prevCell->setRowSpan($rowSpan+1);
- $cell->setVisible(false);
- }
- }
- }
- }
- }
-
- private function getCellText($cell)
- {
- if(($data=$cell->getText())==='' && $cell->getHasControls())
- {
- $controls=$cell->getControls();
- foreach($controls as $control)
- {
- if($control instanceof IDataRenderer)
- return $control->getData();
- }
- }
- return $data;
- }
-
- /**
- * Creates a datagrid item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TDataGridItem created data list item
- */
- protected function createItem($itemIndex,$dataSourceIndex,$itemType)
- {
- return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
- }
-
- private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
- {
- $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
- $this->initializeItem($item,$columns);
- $param=new TDataGridItemEventParameter($item);
- if($dataBind)
- {
- $item->setDataItem($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- }
- else
- {
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- }
- return $item;
- }
-
- /**
- * Initializes a datagrid item and cells inside it
- * @param TDataGrid datagrid item to be initialized
- * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
- */
- protected function initializeItem($item,$columns)
- {
- $cells=$item->getCells();
- $itemType=$item->getItemType();
- $index=0;
- foreach($columns as $column)
- {
- if($itemType===TListItemType::Header)
- $cell=new TTableHeaderCell;
- else
- $cell=new TTableCell;
- if(($id=$column->getID())!=='')
- $item->registerObject($id,$cell);
- $cells->add($cell);
- $column->initializeCell($cell,$index,$itemType);
- $index++;
- }
- }
-
- protected function createPager()
- {
- $pager=new TDataGridPager($this);
- $this->buildPager($pager);
- $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
- $this->getControls()->add($pager);
- return $pager;
- }
-
- /**
- * Builds the pager content based on pager style.
- * @param TDataGridPager the container for the pager
- */
- protected function buildPager($pager)
- {
- switch($this->getPagerStyle()->getMode())
- {
- case TDataGridPagerMode::NextPrev:
- $this->buildNextPrevPager($pager);
- break;
- case TDataGridPagerMode::Numeric:
- $this->buildNumericPager($pager);
- break;
- }
- }
-
- /**
- * Creates a pager button.
- * Depending on the button type, a TLinkButton or a TButton may be created.
- * If it is enabled (clickable), its command name and parameter will also be set.
- * Derived classes may override this method to create additional types of buttons, such as TImageButton.
- * @param mixed the container pager instance of TActiveDatagridPager
- * @param string button type, either LinkButton or PushButton
- * @param boolean whether the button should be enabled
- * @param string caption of the button
- * @param string CommandName corresponding to the OnCommand event of the button
- * @param string CommandParameter corresponding to the OnCommand event of the button
- * @return mixed the button instance
- */
- protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
- {
- if($buttonType===TDataGridPagerButtonType::LinkButton)
- {
- if($enabled)
- $button=new TLinkButton;
- else
- {
- $button=new TLabel;
- $button->setText($text);
- return $button;
- }
- }
- else
- {
- $button=new TButton;
- if(!$enabled)
- $button->setEnabled(false);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCommandParameter($commandParameter);
- $button->setCausesValidation(false);
- return $button;
- }
-
- /**
- * Builds a next-prev pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNextPrevPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $currentPageIndex=$this->getCurrentPageIndex();
- if($currentPageIndex===0)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- $controls->add("\n");
- }
-
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
- $controls->add($label);
- }
- else
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
-
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
- $controls->add($button);
- }
- $controls->add("\n");
- if($currentPageIndex===$this->getPageCount()-1)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
- $controls->add($label);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- }
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a numeric pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNumericPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $pageCount=$this->getPageCount();
- $pageIndex=$this->getCurrentPageIndex()+1;
- $maxButtonCount=$style->getPageButtonCount();
- $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
- $startPageIndex=1;
- $endPageIndex=$buttonCount;
- if($pageIndex>$endPageIndex)
- {
- $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
- if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
- $endPageIndex=$pageCount;
- if($endPageIndex-$startPageIndex+1<$maxButtonCount)
- {
- if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
- $startPageIndex=1;
- }
- }
-
- if($startPageIndex>1)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
- $prevPageIndex=$startPageIndex-1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
- $controls->add($button);
- $controls->add("\n");
- }
-
- for($i=$startPageIndex;$i<=$endPageIndex;++$i)
- {
- if($i===$pageIndex)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
- $controls->add($label);
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
- $controls->add($button);
- }
- if($i<$endPageIndex)
- $controls->add("\n");
- }
-
- if($pageCount>$endPageIndex)
- {
- $controls->add("\n");
- $nextPageIndex=$endPageIndex+1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Automatically generates datagrid columns based on datasource schema
- * @param Traversable data source bound to the datagrid
- * @return TDataGridColumnCollection
- */
- protected function createAutoColumns($dataSource)
- {
- if(!$dataSource)
- return null;
- $autoColumns=$this->getAutoColumns();
- $autoColumns->clear();
- foreach($dataSource as $row)
- {
- foreach($row as $key=>$value)
- {
- $column=new $this->AutoGenerateColumnName;
- if(is_string($key))
- {
- $column->setHeaderText($key);
- $column->setDataField($key);
- $column->setSortExpression($key);
- $autoColumns->add($column);
- }
- else
- {
- $column->setHeaderText(TListItemType::Item);
- $column->setDataField($key);
- $column->setSortExpression(TListItemType::Item);
- $autoColumns->add($column);
- }
- }
- break;
- }
- return $autoColumns;
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- $headerStyle=$this->getViewState('HeaderStyle',null);
- $footerStyle=$this->getViewState('FooterStyle',null);
- $pagerStyle=$this->getViewState('PagerStyle',null);
- $separatorStyle=$this->getViewState('SeparatorStyle',null);
-
- foreach($this->getControls() as $index=>$item)
- {
- if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
- continue;
- $itemType=$item->getItemType();
- switch($itemType)
- {
- case TListItemType::Header:
- if($headerStyle)
- $item->getStyle()->mergeWith($headerStyle);
- if(!$this->getShowHeader())
- $item->setVisible(false);
- break;
- case TListItemType::Footer:
- if($footerStyle)
- $item->getStyle()->mergeWith($footerStyle);
- if(!$this->getShowFooter())
- $item->setVisible(false);
- break;
- case TListItemType::Separator:
- if($separatorStyle)
- $item->getStyle()->mergeWith($separatorStyle);
- break;
- case TListItemType::Item:
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- break;
- case TListItemType::AlternatingItem:
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- break;
- case TListItemType::SelectedItem:
- if($selectedItemStyle)
- $item->getStyle()->mergeWith($selectedItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::EditItem:
- if($editItemStyle)
- $item->getStyle()->mergeWith($editItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::Pager:
- if($pagerStyle)
- {
- $item->getStyle()->mergeWith($pagerStyle);
- if($index===0)
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- else
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- }
- break;
- default:
- break;
- }
- if($this->_columns && $itemType!==TListItemType::Pager)
- {
- $n=$this->_columns->getCount();
- $cells=$item->getCells();
- for($i=0;$i<$n;++$i)
- {
- $cell=$cells->itemAt($i);
- $column=$this->_columns->itemAt($i);
- if(!$column->getVisible())
- $cell->setVisible(false);
- else
- {
- if($itemType===TListItemType::Header)
- $style=$column->getHeaderStyle(false);
- else if($itemType===TListItemType::Footer)
- $style=$column->getFooterStyle(false);
- else
- $style=$column->getItemStyle(false);
- if($style!==null)
- $cell->getStyle()->mergeWith($style);
- }
- }
- }
- }
- }
-
- /**
- * Renders the openning tag for the datagrid control which will render table caption if present.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($caption=$this->getCaption())!=='')
- {
- if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
- $writer->addAttribute('align',strtolower($align));
- $writer->renderBeginTag('caption');
- $writer->write($caption);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the datagrid.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- $this->groupCells();
- if($this->_useEmptyTemplate)
- {
- $control=new TWebControl;
- $control->setID($this->getClientID());
- $control->copyBaseAttributes($this);
- if($this->getHasStyle())
- $control->getStyle()->copyFrom($this->getStyle());
- $control->renderBeginTag($writer);
- $this->renderContents($writer);
- $control->renderEndTag($writer);
- }
- else if($this->getViewState('ItemCount',0)>0)
- {
- $this->applyItemStyles();
- if($this->_topPager)
- {
- $this->_topPager->renderControl($writer);
- $writer->writeLine();
- }
- $this->renderTable($writer);
- if($this->_bottomPager)
- {
- $writer->writeLine();
- $this->_bottomPager->renderControl($writer);
- }
- }
- }
- }
-
- /**
- * Renders the tabular data.
- * @param THtmlWriter writer
- */
- protected function renderTable($writer)
- {
- $this->renderBeginTag($writer);
- if($this->_header && $this->_header->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableHeadStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('thead');
- $this->_header->render($writer);
- $writer->renderEndTag();
- }
- $writer->writeLine();
- if($style=$this->getViewState('TableBodyStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tbody');
- foreach($this->getItems() as $item)
- $item->renderControl($writer);
- $writer->renderEndTag();
-
- if($this->_footer && $this->_footer->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableFootStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tfoot');
- $this->_footer->render($writer);
- $writer->renderEndTag();
- }
-
- $writer->writeLine();
- $this->renderEndTag($writer);
- }
-}
-
-/**
- * TDataGridItemEventParameter class
- *
- * TDataGridItemEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemEventParameter extends TEventParameter
-{
- /**
- * The TDataGridItem control responsible for the event.
- * @var TDataGridItem
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item related with the corresponding event
- */
- public function __construct(TDataGridItem $item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TDataGridItem datagrid item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataGridPagerEventParameter class
- *
- * TDataGridPagerEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
- * The {@link getPager Pager} property indicates the datagrid pager related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerEventParameter extends TEventParameter
-{
- /**
- * The TDataGridPager control responsible for the event.
- * @var TDataGridPager
- */
- protected $_pager=null;
-
- /**
- * Constructor.
- * @param TDataGridPager datagrid pager related with the corresponding event
- */
- public function __construct(TDataGridPager $pager)
- {
- $this->_pager=$pager;
- }
-
- /**
- * @return TDataGridPager datagrid pager related with the corresponding event
- */
- public function getPager()
- {
- return $this->_pager;
- }
-}
-
-/**
- * TDataGridCommandEventParameter class
- *
- * TDataGridCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TDataGridItem the TDataGridItem control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>Command</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TDataGridItem the TDataGridItem control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>Command</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataGridSortCommandEventParameter class
- *
- * TDataGridSortCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
- * gives the sort expression carried with the sort command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridSortCommandEventParameter extends TEventParameter
-{
- /**
- * @var string sort expression
- */
- private $_sortExpression='';
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param TDataGridCommandEventParameter command event parameter
- */
- public function __construct($source,TDataGridCommandEventParameter $param)
- {
- $this->_source=$source;
- $this->_sortExpression=$param->getCommandParameter();
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return string sort expression
- */
- public function getSortExpression()
- {
- return $this->_sortExpression;
- }
-}
-
-/**
- * TDataGridPageChangedEventParameter class
- *
- * TDataGridPageChangedEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
- * returns the new page index carried with the page command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPageChangedEventParameter extends TEventParameter
-{
- /**
- * @var integer new page index
- */
- private $_newIndex;
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param integer new page index
- */
- public function __construct($source,$newPageIndex)
- {
- $this->_source=$source;
- $this->_newIndex=$newPageIndex;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return integer new page index
- */
- public function getNewPageIndex()
- {
- return $this->_newIndex;
- }
-}
-
-/**
- * TDataGridItem class
- *
- * A TDataGridItem control represents an item in the {@link TDataGrid} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
- * gives the index of the item from the bound data source.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItem extends TTableRow implements INamingContainer
-{
- /**
- * @var integer index of the data item in the Items collection of datagrid
- */
- private $_itemIndex='';
- /**
- * @var integer index of the item from the bound data source
- */
- private $_dataSourceIndex=0;
- /**
- * type of the TDataGridItem
- * @var string
- */
- private $_itemType='';
- /**
- * value of the data item
- * @var mixed
- */
- private $_data=null;
-
- /**
- * Constructor.
- * @param integer zero-based index of the item in the item collection of datagrid
- * @param TListItemType item type
- */
- public function __construct($itemIndex,$dataSourceIndex,$itemType)
- {
- $this->_itemIndex=$itemIndex;
- $this->_dataSourceIndex=$dataSourceIndex;
- $this->setItemType($itemType);
- if($itemType===TListItemType::Header)
- $this->setTableSection(TTableRowSection::Header);
- else if($itemType===TListItemType::Footer)
- $this->setTableSection(TTableRowSection::Footer);
- }
-
- /**
- * @return TListItemType item type.
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datagrid
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * @return integer the index of the datagrid item from the bound data source
- */
- public function getDataSourceIndex()
- {
- return $this->_dataSourceIndex;
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-
-/**
- * TDataGridPager class.
- *
- * TDataGridPager represents a datagrid pager.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPager extends TPanel implements INamingContainer
-{
- private $_dataGrid;
-
- /**
- * Constructor.
- * @param TDataGrid datagrid object
- */
- public function __construct($dataGrid)
- {
- $this->_dataGrid=$dataGrid;
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * @return TDataGrid the datagrid owning this pager
- */
- public function getDataGrid()
- {
- return $this->_dataGrid;
- }
-
- /**
- * @return string item type.
- */
- public function getItemType()
- {
- return TListItemType::Pager;
- }
-}
-
-
-/**
- * TDataGridItemCollection class.
- *
- * TDataGridItemCollection represents a collection of data grid items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TDataGridItem.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridItem)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
- }
-}
-
-/**
- * TDataGridColumnCollection class.
- *
- * TDataGridColumnCollection represents a collection of data grid columns.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridColumnCollection extends TList
-{
- /**
- * the control that owns this collection.
- * @var TControl
- */
- private $_o;
-
- /**
- * Constructor.
- * @param TDataGrid the control that owns this collection.
- */
- public function __construct(TDataGrid $owner)
- {
- $this->_o=$owner;
- }
-
- /**
- * @return TDataGrid 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 inserting only TDataGridColumn.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridColumn)
- {
- $item->setOwner($this->_o);
- parent::insertAt($index,$item);
- }
- else
- throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
- }
-}
-
-/**
- * TDataGridPagerMode class.
- * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
- *
- * The following enumerable values are defined:
- * - NextPrev: pager buttons are displayed as next and previous pages
- * - Numeric: pager buttons are displayed as numeric page numbers
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerMode extends TEnumerable
-{
- const NextPrev='NextPrev';
- const Numeric='Numeric';
-}
-
-
-/**
- * TDataGridPagerButtonType class.
- * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form submit buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerButtonType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
-}
-
-
-/**
- * TDataGridPagerPosition class.
- * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
- *
- * The following enumerable values are defined:
- * - Bottom: pager appears only at the bottom of the data grid.
- * - Top: pager appears only at the top of the data grid.
- * - TopAndBottom: pager appears on both top and bottom of the data grid.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerPosition extends TEnumerable
-{
- const Bottom='Bottom';
- const Top='Top';
- const TopAndBottom='TopAndBottom';
-}
-
+<?php +/** + * TDataGrid related class files. + * This file contains the definition of the following classes: + * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection, + * TDataGridPagerStyle, TDataGridItemEventParameter, + * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter, + * TDataGridPageChangedEventParameter + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes + */ +Prado::using('System.Web.UI.WebControls.TBaseDataList'); +Prado::using('System.Collections.TPagedDataSource'); +Prado::using('System.Collections.TDummyDataSource'); +Prado::using('System.Web.UI.WebControls.TTable'); +Prado::using('System.Web.UI.WebControls.TPanel'); +Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle'); + +/** + * TDataGrid class + * + * TDataGrid represents a data bound and updatable grid control. + * + * To populate data into the datagrid, sets its {@link setDataSource DataSource} + * to a tabular data source and call {@link dataBind()}. + * Each row of data will be represented by an item in the {@link getItems Items} + * collection of the datagrid. + * + * An item can be at one of three states: browsing, selected and edit. + * The state determines how the item will be displayed. For example, if an item + * is in edit state, it may be displayed as a table row with input text boxes + * if the columns are of type {@link TBoundColumn}; and if in browsing state, + * they are displayed as static text. + * + * To change the state of an item, set {@link setEditItemIndex EditItemIndex} + * or {@link setSelectedItemIndex SelectedItemIndex} property. + * + * Each datagrid item has a {@link TDataGridItem::getItemType type} + * which tells the position and state of the item in the datalist. An item in the header + * of the repeater is of type Header. A body item may be of either + * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item + * index is odd or even, whether it is being selected or edited. + * + * A datagrid is specified with a list of columns. Each column specifies how the corresponding + * table column will be displayed. For example, the header/footer text of that column, + * the cells in that column, and so on. The following column types are currently + * provided by the framework, + * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. + * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons + * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. + * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state + * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. + * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. + * - {@link TTemplateColumn}, displaying content based on templates. + * + * There are three ways to specify columns for a datagrid. + * <ul> + * <li>Automatically generated based on data source. + * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true, + * a list of columns will be automatically generated based on the schema of the data source. + * Each column corresponds to a column of the data.</li> + * <li>Specified in template. For example, + * <code> + * <com:TDataGrid ...> + * <com:TBoundColumn .../> + * <com:TEditCommandColumn .../> + * </com:TDataGrid> + * </code> + * </li> + * <li>Manually created in code. Columns can be manipulated via + * the {@link setColumns Columns} property of the datagrid. For example, + * <code> + * $column=new TBoundColumn; + * $datagrid->Columns[]=$column; + * </code> + * </li> + * </ul> + * Note, automatically generated columns cannot be accessed via + * the {@link getColumns Columns} property. + * + * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting} + * is set to true, a column with nonempty {@link setSortExpression SortExpression} + * will have its header text displayed as a clickable link button. + * Clicking on the link button will raise {@link onSortCommand OnSortCommand} + * event. You can respond to this event, sort the data source according + * to the event parameter, and then invoke {@link databind()} on the datagrid + * to show to end users the sorted data. + * + * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging} + * is set to true, a pager will be displayed on top and/or bottom of the table. + * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle} + * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged} + * event. You can respond to this event, specify the page to be displayed by + * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property, + * and then invoke {@link databind()} on the datagrid to show to end users + * a new page of data. + * + * TDataGrid supports two kinds of paging. The first one is based on the number of data items in + * datasource. The number of pages {@link getPageCount PageCount} is calculated based + * the item number and the {@link setPageSize PageSize} property. + * The datagrid will manage which section of the data source to be displayed + * based on the {@link setCurrentPageIndex CurrentPageIndex} property. + * The second approach calculates the page number based on the + * {@link setVirtualItemCount VirtualItemCount} property and + * the {@link setPageSize PageSize} property. The datagrid will always + * display from the beginning of the datasource up to the number of + * {@link setPageSize PageSize} data items. This approach is especially + * useful when the datasource may contain too many data items to be managed by + * the datagrid efficiently. + * + * When the datagrid contains a button control that raises an {@link onCommand OnCommand} + * event, the event will be bubbled up to the datagrid control. + * If the event's command name is recognizable by the datagrid control, + * a corresponding item event will be raised. The following item events will be + * raised upon a specific command: + * - OnEditCommand, if CommandName=edit + * - OnCancelCommand, if CommandName=cancel + * - OnSelectCommand, if CommandName=select + * - OnDeleteCommand, if CommandName=delete + * - OnUpdateCommand, if CommandName=update + * - onPageIndexChanged, if CommandName=page + * - OnSortCommand, if CommandName=sort + * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to + * the above specific command events. + * + * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for + * every newly created datagrid item. You can respond to this event to customize + * the content or style of the newly created item. + * + * Note, the data bound to the datagrid are reset to null after databinding. + * There are several ways to access the data associated with a datagrid row: + * - Access the data in {@link onItemDataBound OnItemDataBound} event + * - Use {@link getDataKeys DataKeys} to obtain the data key associated with + * the specified datagrid row and use the key to fetch the corresponding data + * from some persistent storage such as DB. + * - Save the data in viewstate and get it back during postbacks. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGrid extends TBaseDataList implements INamingContainer +{ + /** + * datagrid item types + * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead. + */ + const IT_HEADER='Header'; + const IT_FOOTER='Footer'; + const IT_ITEM='Item'; + const IT_SEPARATOR='Separator'; + const IT_ALTERNATINGITEM='AlternatingItem'; + const IT_EDITITEM='EditItem'; + const IT_SELECTEDITEM='SelectedItem'; + const IT_PAGER='Pager'; + + /** + * Command name that TDataGrid understands. + */ + const CMD_SELECT='Select'; + const CMD_EDIT='Edit'; + const CMD_UPDATE='Update'; + const CMD_DELETE='Delete'; + const CMD_CANCEL='Cancel'; + const CMD_SORT='Sort'; + const CMD_PAGE='Page'; + const CMD_PAGE_NEXT='Next'; + const CMD_PAGE_PREV='Previous'; + const CMD_PAGE_FIRST='First'; + const CMD_PAGE_LAST='Last'; + + /** + * @var TDataGridColumnCollection manually created column collection + */ + private $_columns=null; + /** + * @var TDataGridColumnCollection automatically created column collection + */ + private $_autoColumns=null; + /** + * @var TList all columns including both manually and automatically created columns + */ + private $_allColumns=null; + /** + * @var TDataGridItemCollection datagrid item collection + */ + private $_items=null; + /** + * @var TDataGridItem header item + */ + private $_header=null; + /** + * @var TDataGridItem footer item + */ + private $_footer=null; + /** + * @var TPagedDataSource paged data source object + */ + private $_pagedDataSource=null; + private $_topPager=null; + private $_bottomPager=null; + /** + * @var ITemplate template used when empty data is bounded + */ + private $_emptyTemplate=null; + /** + * @var boolean whether empty template is effective + */ + private $_useEmptyTemplate=false; + + /** + * @return string tag name (table) of the datagrid + */ + protected function getTagName() + { + return 'table'; + } + + /** + * @return string Name of the class used in AutoGenerateColumns mode + */ + protected function getAutoGenerateColumnName() + { + return 'TBoundColumn'; + } + + /** + * Adds objects parsed in template to datagrid. + * Datagrid columns are added into {@link getColumns Columns} collection. + * @param mixed object parsed in template + */ + public function addParsedObject($object) + { + if($object instanceof TDataGridColumn) + $this->getColumns()->add($object); + else + parent::addParsedObject($object); // this is needed by EmptyTemplate + } + + /** + * @return TDataGridColumnCollection manually specified datagrid columns + */ + public function getColumns() + { + if(!$this->_columns) + $this->_columns=new TDataGridColumnCollection($this); + return $this->_columns; + } + + /** + * @return TDataGridColumnCollection automatically generated datagrid columns + */ + public function getAutoColumns() + { + if(!$this->_autoColumns) + $this->_autoColumns=new TDataGridColumnCollection($this); + return $this->_autoColumns; + } + + /** + * @return TDataGridItemCollection datagrid item collection + */ + public function getItems() + { + if(!$this->_items) + $this->_items=new TDataGridItemCollection; + return $this->_items; + } + + /** + * @return integer number of items + */ + public function getItemCount() + { + return $this->_items?$this->_items->getCount():0; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableStyle} to be used by datagrid. + * @return TTableStyle control style to be used + */ + protected function createStyle() + { + return new TTableStyle; + } + + /** + * @return string the URL of the background image for the datagrid + */ + public function getBackImageUrl() + { + return $this->getStyle()->getBackImageUrl(); + } + + /** + * @param string the URL of the background image for the datagrid + */ + public function setBackImageUrl($value) + { + $this->getStyle()->setBackImageUrl($value); + } + + /** + * @return TTableItemStyle the style for every item + */ + public function getItemStyle() + { + if(($style=$this->getViewState('ItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for each alternating item + */ + public function getAlternatingItemStyle() + { + if(($style=$this->getViewState('AlternatingItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('AlternatingItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for selected item + */ + public function getSelectedItemStyle() + { + if(($style=$this->getViewState('SelectedItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SelectedItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for edit item + */ + public function getEditItemStyle() + { + if(($style=$this->getViewState('EditItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('EditItemStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle() + { + if(($style=$this->getViewState('FooterStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @return TDataGridPagerStyle the style for pager + */ + public function getPagerStyle() + { + if(($style=$this->getViewState('PagerStyle',null))===null) + { + $style=new TDataGridPagerStyle; + $this->setViewState('PagerStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for thead element, if any + * @since 3.1.1 + */ + public function getTableHeadStyle() + { + if(($style=$this->getViewState('TableHeadStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableHeadStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for tbody element, if any + * @since 3.1.1 + */ + public function getTableBodyStyle() + { + if(($style=$this->getViewState('TableBodyStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableBodyStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style for tfoot element, if any + * @since 3.1.1 + */ + public function getTableFootStyle() + { + if(($style=$this->getViewState('TableFootStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('TableFootStyle',$style,null); + } + return $style; + } + + /** + * @return string caption for the datagrid + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string caption for the datagrid + */ + public function setCaption($value) + { + $this->setViewState('Caption',$value,''); + } + + /** + * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet); + } + + /** + * @param TTableCaptionAlign datagrid caption alignment. Valid values include + */ + public function setCaptionAlign($value) + { + $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet); + } + + /** + * @return TDataGridItem the header item + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return TDataGridItem the footer item + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled. + */ + public function getTopPager() + { + return $this->_topPager; + } + + /** + * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled. + */ + public function getBottomPager() + { + return $this->_bottomPager; + } + + /** + * @return TDataGridItem the selected item, null if no item is selected. + */ + public function getSelectedItem() + { + $index=$this->getSelectedItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the selected item in {@link getItems Items}. + * A value -1 means no item selected. + */ + public function getSelectedItemIndex() + { + return $this->getViewState('SelectedItemIndex',-1); + } + + /** + * Selects an item by its index in {@link getItems Items}. + * Previously selected item will be un-selected. + * If the item to be selected is already in edit mode, it will remain in edit mode. + * If the index is less than 0, any existing selection will be cleared up. + * @param integer the selected item index + */ + public function setSelectedItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getSelectedItemIndex())!==$value) + { + $this->setViewState('SelectedItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + { + $item=$items->itemAt($current); + if($item->getItemType()!==TListItemType::EditItem) + $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); + } + if($value>=0 && $value<$itemCount) + { + $item=$items->itemAt($value); + if($item->getItemType()!==TListItemType::EditItem) + $item->setItemType(TListItemType::SelectedItem); + } + } + } + + /** + * @return TDataGridItem the edit item + */ + public function getEditItem() + { + $index=$this->getEditItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the edit item in {@link getItems Items}. + * A value -1 means no item is in edit mode. + */ + public function getEditItemIndex() + { + return $this->getViewState('EditItemIndex',-1); + } + + /** + * Edits an item by its index in {@link getItems Items}. + * Previously editting item will change to normal item state. + * If the index is less than 0, any existing edit item will be cleared up. + * @param integer the edit item index + */ + public function setEditItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getEditItemIndex())!==$value) + { + $this->setViewState('EditItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item); + if($value>=0 && $value<$itemCount) + $items->itemAt($value)->setItemType(TListItemType::EditItem); + } + } + + /** + * @return boolean whether sorting is enabled. Defaults to false. + */ + public function getAllowSorting() + { + return $this->getViewState('AllowSorting',false); + } + + /** + * @param boolean whether sorting is enabled + */ + public function setAllowSorting($value) + { + $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether datagrid columns should be automatically generated. Defaults to true. + */ + public function getAutoGenerateColumns() + { + return $this->getViewState('AutoGenerateColumns',true); + } + + /** + * @param boolean whether datagrid columns should be automatically generated + */ + public function setAutoGenerateColumns($value) + { + $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the header should be displayed. Defaults to true. + */ + public function getShowHeader() + { + return $this->getViewState('ShowHeader',true); + } + + /** + * @param boolean whether the header should be displayed + */ + public function setShowHeader($value) + { + $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the footer should be displayed. Defaults to false. + */ + public function getShowFooter() + { + return $this->getViewState('ShowFooter',false); + } + + /** + * @param boolean whether the footer should be displayed + */ + public function setShowFooter($value) + { + $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return ITemplate the template applied when no data is bound to the datagrid + */ + public function getEmptyTemplate() + { + return $this->_emptyTemplate; + } + + /** + * @param ITemplate the template applied when no data is bound to the datagrid + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEmptyTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_emptyTemplate=$value; + else + throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate'); + } + + /** + * This method overrides parent's implementation to handle + * {@link onItemCommand OnItemCommand} event which is bubbled from + * {@link TDataGridItem} child controls. + * If the event parameter is {@link TDataGridCommandEventParameter} and + * the command name is a recognized one, which includes 'select', 'edit', + * 'delete', 'update', and 'cancel' (case-insensitive), then a + * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). + * This method should only be used by control developers. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TDataGridCommandEventParameter) + { + $this->onItemCommand($param); + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_SELECT)===0) + { + $this->setSelectedItemIndex($param->getItem()->getItemIndex()); + $this->onSelectedIndexChanged($param); + return true; + } + else if(strcasecmp($command,self::CMD_EDIT)===0) + { + $this->onEditCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_DELETE)===0) + { + $this->onDeleteCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_UPDATE)===0) + { + $this->onUpdateCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_CANCEL)===0) + { + $this->onCancelCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_SORT)===0) + { + $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE)===0) + { + $p=$param->getCommandParameter(); + if(strcasecmp($p,self::CMD_PAGE_NEXT)===0) + $pageIndex=$this->getCurrentPageIndex()+1; + else if(strcasecmp($p,self::CMD_PAGE_PREV)===0) + $pageIndex=$this->getCurrentPageIndex()-1; + else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0) + $pageIndex=0; + else if(strcasecmp($p,self::CMD_PAGE_LAST)===0) + $pageIndex=$this->getPageCount()-1; + else + $pageIndex=TPropertyValue::ensureInteger($p)-1; + $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex)); + return true; + } + } + return false; + } + + /** + * Raises <b>OnCancelCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event + * with <b>cancel</b> command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onCancelCommand($param) + { + $this->raiseEvent('OnCancelCommand',$this,$param); + } + + /** + * Raises <b>OnDeleteCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event + * with <b>delete</b> command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onDeleteCommand($param) + { + $this->raiseEvent('OnDeleteCommand',$this,$param); + } + + /** + * Raises <b>OnEditCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event + * with <b>edit</b> command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onEditCommand($param) + { + $this->raiseEvent('OnEditCommand',$this,$param); + } + + /** + * Raises <b>OnItemCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event. + * @param TDataGridCommandEventParameter event parameter + */ + public function onItemCommand($param) + { + $this->raiseEvent('OnItemCommand',$this,$param); + } + + /** + * Raises <b>OnSortCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event + * with <b>sort</b> command name. + * @param TDataGridSortCommandEventParameter event parameter + */ + public function onSortCommand($param) + { + $this->raiseEvent('OnSortCommand',$this,$param); + } + + /** + * Raises <b>OnUpdateCommand</b> event. + * This method is invoked when a button control raises <b>OnCommand</b> event + * with <b>update</b> command name. + * @param TDataGridCommandEventParameter event parameter + */ + public function onUpdateCommand($param) + { + $this->raiseEvent('OnUpdateCommand',$this,$param); + } + + /** + * Raises <b>OnItemCreated</b> event. + * This method is invoked right after a datagrid item is created and before + * added to page hierarchy. + * @param TDataGridItemEventParameter event parameter + */ + public function onItemCreated($param) + { + $this->raiseEvent('OnItemCreated',$this,$param); + } + + /** + * Raises <b>OnPagerCreated</b> event. + * This method is invoked right after a datagrid pager is created and before + * added to page hierarchy. + * @param TDataGridPagerEventParameter event parameter + */ + public function onPagerCreated($param) + { + $this->raiseEvent('OnPagerCreated',$this,$param); + } + + /** + * Raises <b>OnItemDataBound</b> event. + * This method is invoked for each datagrid item after it performs + * databinding. + * @param TDataGridItemEventParameter event parameter + */ + public function onItemDataBound($param) + { + $this->raiseEvent('OnItemDataBound',$this,$param); + } + + /** + * Raises <b>OnPageIndexChanged</b> event. + * This method is invoked when current page is changed. + * @param TDataGridPageChangedEventParameter event parameter + */ + public function onPageIndexChanged($param) + { + $this->raiseEvent('OnPageIndexChanged',$this,$param); + } + + /** + * Saves item count in viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if(!$this->getEnableViewState(true)) + return; + if($this->_items) + $this->setViewState('ItemCount',$this->_items->getCount(),0); + else + $this->clearViewState('ItemCount'); + if($this->_autoColumns) + { + $state=array(); + foreach($this->_autoColumns as $column) + $state[]=$column->saveState(); + $this->setViewState('AutoColumns',$state,array()); + } + else + $this->clearViewState('AutoColumns'); + if($this->_columns) + { + $state=array(); + foreach($this->_columns as $column) + $state[]=$column->saveState(); + $this->setViewState('Columns',$state,array()); + } + else + $this->clearViewState('Columns'); + } + + /** + * Loads item count information from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + if(!$this->getEnableViewState(true)) + return; + if(!$this->getIsDataBound()) + { + $state=$this->getViewState('AutoColumns',array()); + if(!empty($state)) + { + $this->_autoColumns=new TDataGridColumnCollection($this); + foreach($state as $st) + { + $column=new $this->AutoGenerateColumnName; + $column->loadState($st); + $this->_autoColumns->add($column); + } + } + else + $this->_autoColumns=null; + $state=$this->getViewState('Columns',array()); + if($this->_columns && $this->_columns->getCount()===count($state)) + { + $i=0; + foreach($this->_columns as $column) + { + $column->loadState($state[$i]); + $i++; + } + } + $this->restoreGridFromViewState(); + } + } + + /** + * Clears up all items in the datagrid. + */ + public function reset() + { + $this->getControls()->clear(); + $this->getItems()->clear(); + $this->_header=null; + $this->_footer=null; + $this->_topPager=null; + $this->_bottomPager=null; + $this->_useEmptyTemplate=false; + } + + /** + * Restores datagrid content from viewstate. + */ + protected function restoreGridFromViewState() + { + $this->reset(); + + $allowPaging=$this->getAllowPaging(); + + $itemCount=$this->getViewState('ItemCount',0); + $dsIndex=$this->getViewState('DataSourceIndex',0); + + $columns=new TList($this->getColumns()); + $columns->mergeWith($this->_autoColumns); + $this->_allColumns=$columns; + + $items=$this->getItems(); + + if($columns->getCount()) + { + foreach($columns as $column) + $column->initialize(); + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + for($index=0;$index<$itemCount;++$index) + { + if($index===0) + { + if($allowPaging) + $this->_topPager=$this->createPager(); + $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns); + } + if($index===$editIndex) + $itemType=TListItemType::EditItem; + else if($index===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else if($index % 2) + $itemType=TListItemType::AlternatingItem; + else + $itemType=TListItemType::Item; + $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns)); + $dsIndex++; + } + if($index>0) + { + $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns); + if($allowPaging) + $this->_bottomPager=$this->createPager(); + } + } + if(!$dsIndex && $this->_emptyTemplate!==null) + { + $this->_useEmptyTemplate=true; + $this->_emptyTemplate->instantiateIn($this); + } + } + + /** + * Performs databinding to populate datagrid items from data source. + * This method is invoked by {@link dataBind()}. + * You may override this function to provide your own way of data population. + * @param Traversable the bound data + */ + protected function performDataBinding($data) + { + $this->reset(); + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + + // get all columns + if($this->getAutoGenerateColumns()) + { + $columns=new TList($this->getColumns()); + $autoColumns=$this->createAutoColumns($data); + $columns->mergeWith($autoColumns); + } + else + $columns=$this->getColumns(); + $this->_allColumns=$columns; + + $items=$this->getItems(); + + $index=0; + $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource); + $dsIndex=$allowPaging?$data->getFirstIndexInPage():0; + $this->setViewState('DataSourceIndex',$dsIndex,0); + if($columns->getCount()) + { + foreach($columns as $column) + $column->initialize(); + + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + foreach($data as $key=>$row) + { + if($keyField!=='') + $keys->add($this->getDataFieldValue($row,$keyField)); + else + $keys->add($key); + if($index===0) + { + if($allowPaging) + $this->_topPager=$this->createPager(); + $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns); + } + if($index===$editIndex) + $itemType=TListItemType::EditItem; + else if($index===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else if($index % 2) + $itemType=TListItemType::AlternatingItem; + else + $itemType=TListItemType::Item; + $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns)); + $index++; + $dsIndex++; + } + if($index>0) + { + $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns); + if($allowPaging) + $this->_bottomPager=$this->createPager(); + } + } + $this->setViewState('ItemCount',$index,0); + if(!$dsIndex && $this->_emptyTemplate!==null) + { + $this->_useEmptyTemplate=true; + $this->_emptyTemplate->instantiateIn($this); + $this->dataBindChildren(); + } + } + + /** + * Merges consecutive cells who have the same text. + * @since 3.1.1 + */ + private function groupCells() + { + if(($columns=$this->_allColumns)===null) + return; + $items=$this->getItems(); + foreach($columns as $id=>$column) + { + if(!$column->getEnableCellGrouping()) + continue; + $prevCell=null; + $prevCellText=null; + foreach($items as $item) + { + $itemType=$item->getItemType(); + $cell=$item->getCells()->itemAt($id); + if(!$cell->getVisible()) + continue; + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) + { + if(($cellText=$this->getCellText($cell))==='') + { + $prevCell=null; + $prevCellText=null; + continue; + } + if($prevCell===null || $prevCellText!==$cellText) + { + $prevCell=$cell; + $prevCellText=$cellText; + } + else + { + if(($rowSpan=$prevCell->getRowSpan())===0) + $rowSpan=1; + $prevCell->setRowSpan($rowSpan+1); + $cell->setVisible(false); + } + } + } + } + } + + private function getCellText($cell) + { + if(($data=$cell->getText())==='' && $cell->getHasControls()) + { + $controls=$cell->getControls(); + foreach($controls as $control) + { + if($control instanceof IDataRenderer) + return $control->getData(); + } + } + return $data; + } + + /** + * Creates a datagrid item instance based on the item type and index. + * @param integer zero-based item index + * @param TListItemType item type + * @return TDataGridItem created data list item + */ + protected function createItem($itemIndex,$dataSourceIndex,$itemType) + { + return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType); + } + + private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns) + { + $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType); + $this->initializeItem($item,$columns); + $param=new TDataGridItemEventParameter($item); + if($dataBind) + { + $item->setDataItem($dataItem); + $this->onItemCreated($param); + $this->getControls()->add($item); + $item->dataBind(); + $this->onItemDataBound($param); + } + else + { + $this->onItemCreated($param); + $this->getControls()->add($item); + } + return $item; + } + + /** + * Initializes a datagrid item and cells inside it + * @param TDataGrid datagrid item to be initialized + * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item + */ + protected function initializeItem($item,$columns) + { + $cells=$item->getCells(); + $itemType=$item->getItemType(); + $index=0; + foreach($columns as $column) + { + if($itemType===TListItemType::Header) + $cell=new TTableHeaderCell; + else + $cell=new TTableCell; + if(($id=$column->getID())!=='') + $item->registerObject($id,$cell); + $cells->add($cell); + $column->initializeCell($cell,$index,$itemType); + $index++; + } + } + + protected function createPager() + { + $pager=new TDataGridPager($this); + $this->buildPager($pager); + $this->onPagerCreated(new TDataGridPagerEventParameter($pager)); + $this->getControls()->add($pager); + return $pager; + } + + /** + * Builds the pager content based on pager style. + * @param TDataGridPager the container for the pager + */ + protected function buildPager($pager) + { + switch($this->getPagerStyle()->getMode()) + { + case TDataGridPagerMode::NextPrev: + $this->buildNextPrevPager($pager); + break; + case TDataGridPagerMode::Numeric: + $this->buildNumericPager($pager); + break; + } + } + + /** + * Creates a pager button. + * Depending on the button type, a TLinkButton or a TButton may be created. + * If it is enabled (clickable), its command name and parameter will also be set. + * Derived classes may override this method to create additional types of buttons, such as TImageButton. + * @param mixed the container pager instance of TActiveDatagridPager + * @param string button type, either LinkButton or PushButton + * @param boolean whether the button should be enabled + * @param string caption of the button + * @param string CommandName corresponding to the OnCommand event of the button + * @param string CommandParameter corresponding to the OnCommand event of the button + * @return mixed the button instance + */ + protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter) + { + if($buttonType===TDataGridPagerButtonType::LinkButton) + { + if($enabled) + $button=new TLinkButton; + else + { + $button=new TLabel; + $button->setText($text); + return $button; + } + } + else + { + $button=new TButton; + if(!$enabled) + $button->setEnabled(false); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCommandParameter($commandParameter); + $button->setCausesValidation(false); + return $button; + } + + /** + * Builds a next-prev pager + * @param TDataGridPager the container for the pager + */ + protected function buildNextPrevPager($pager) + { + $style=$this->getPagerStyle(); + $buttonType=$style->getButtonType(); + $controls=$pager->getControls(); + $currentPageIndex=$this->getCurrentPageIndex(); + if($currentPageIndex===0) + { + if(($text=$style->getFirstPageText())!=='') + { + $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); + $controls->add($label); + $controls->add("\n"); + } + + $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'',''); + $controls->add($label); + } + else + { + if(($text=$style->getFirstPageText())!=='') + { + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); + $controls->add($button); + $controls->add("\n"); + } + + $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV); + $controls->add($button); + } + $controls->add("\n"); + if($currentPageIndex===$this->getPageCount()-1) + { + $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'',''); + $controls->add($label); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $label=$this->createPagerButton($pager,$buttonType,false,$text,'',''); + $controls->add($label); + } + } + else + { + $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT); + $controls->add($button); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); + $controls->add($button); + } + } + } + + /** + * Builds a numeric pager + * @param TDataGridPager the container for the pager + */ + protected function buildNumericPager($pager) + { + $style=$this->getPagerStyle(); + $buttonType=$style->getButtonType(); + $controls=$pager->getControls(); + $pageCount=$this->getPageCount(); + $pageIndex=$this->getCurrentPageIndex()+1; + $maxButtonCount=$style->getPageButtonCount(); + $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount; + $startPageIndex=1; + $endPageIndex=$buttonCount; + if($pageIndex>$endPageIndex) + { + $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1; + if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount) + $endPageIndex=$pageCount; + if($endPageIndex-$startPageIndex+1<$maxButtonCount) + { + if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1) + $startPageIndex=1; + } + } + + if($startPageIndex>1) + { + if(($text=$style->getFirstPageText())!=='') + { + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST); + $controls->add($button); + $controls->add("\n"); + } + $prevPageIndex=$startPageIndex-1; + $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex"); + $controls->add($button); + $controls->add("\n"); + } + + for($i=$startPageIndex;$i<=$endPageIndex;++$i) + { + if($i===$pageIndex) + { + $label=$this->createPagerButton($pager,$buttonType,false,"$i",'',''); + $controls->add($label); + } + else + { + $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i"); + $controls->add($button); + } + if($i<$endPageIndex) + $controls->add("\n"); + } + + if($pageCount>$endPageIndex) + { + $controls->add("\n"); + $nextPageIndex=$endPageIndex+1; + $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex"); + $controls->add($button); + if(($text=$style->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST); + $controls->add($button); + } + } + } + + /** + * Automatically generates datagrid columns based on datasource schema + * @param Traversable data source bound to the datagrid + * @return TDataGridColumnCollection + */ + protected function createAutoColumns($dataSource) + { + if(!$dataSource) + return null; + $autoColumns=$this->getAutoColumns(); + $autoColumns->clear(); + foreach($dataSource as $row) + { + foreach($row as $key=>$value) + { + $column=new $this->AutoGenerateColumnName; + if(is_string($key)) + { + $column->setHeaderText($key); + $column->setDataField($key); + $column->setSortExpression($key); + $autoColumns->add($column); + } + else + { + $column->setHeaderText(TListItemType::Item); + $column->setDataField($key); + $column->setSortExpression(TListItemType::Item); + $autoColumns->add($column); + } + } + break; + } + return $autoColumns; + } + + /** + * Applies styles to items, header, footer and separators. + * Item styles are applied in a hierarchical way. Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, + * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + */ + protected function applyItemStyles() + { + $itemStyle=$this->getViewState('ItemStyle',null); + + $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); + if($itemStyle!==null) + { + if($alternatingItemStyle===null) + $alternatingItemStyle=$itemStyle; + else + $alternatingItemStyle->mergeWith($itemStyle); + } + + $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); + + $editItemStyle=$this->getViewState('EditItemStyle',null); + if($selectedItemStyle!==null) + { + if($editItemStyle===null) + $editItemStyle=$selectedItemStyle; + else + $editItemStyle->mergeWith($selectedItemStyle); + } + + $headerStyle=$this->getViewState('HeaderStyle',null); + $footerStyle=$this->getViewState('FooterStyle',null); + $pagerStyle=$this->getViewState('PagerStyle',null); + $separatorStyle=$this->getViewState('SeparatorStyle',null); + + foreach($this->getControls() as $index=>$item) + { + if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager)) + continue; + $itemType=$item->getItemType(); + switch($itemType) + { + case TListItemType::Header: + if($headerStyle) + $item->getStyle()->mergeWith($headerStyle); + if(!$this->getShowHeader()) + $item->setVisible(false); + break; + case TListItemType::Footer: + if($footerStyle) + $item->getStyle()->mergeWith($footerStyle); + if(!$this->getShowFooter()) + $item->setVisible(false); + break; + case TListItemType::Separator: + if($separatorStyle) + $item->getStyle()->mergeWith($separatorStyle); + break; + case TListItemType::Item: + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + break; + case TListItemType::AlternatingItem: + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + break; + case TListItemType::SelectedItem: + if($selectedItemStyle) + $item->getStyle()->mergeWith($selectedItemStyle); + if($index % 2==1) + { + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + } + else + { + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + } + break; + case TListItemType::EditItem: + if($editItemStyle) + $item->getStyle()->mergeWith($editItemStyle); + if($index % 2==1) + { + if($itemStyle) + $item->getStyle()->mergeWith($itemStyle); + } + else + { + if($alternatingItemStyle) + $item->getStyle()->mergeWith($alternatingItemStyle); + } + break; + case TListItemType::Pager: + if($pagerStyle) + { + $item->getStyle()->mergeWith($pagerStyle); + if($index===0) + { + if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible()) + $item->setVisible(false); + } + else + { + if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible()) + $item->setVisible(false); + } + } + break; + default: + break; + } + if($this->_columns && $itemType!==TListItemType::Pager) + { + $n=$this->_columns->getCount(); + $cells=$item->getCells(); + for($i=0;$i<$n;++$i) + { + $cell=$cells->itemAt($i); + $column=$this->_columns->itemAt($i); + if(!$column->getVisible()) + $cell->setVisible(false); + else + { + if($itemType===TListItemType::Header) + $style=$column->getHeaderStyle(false); + else if($itemType===TListItemType::Footer) + $style=$column->getFooterStyle(false); + else + $style=$column->getItemStyle(false); + if($style!==null) + $cell->getStyle()->mergeWith($style); + } + } + } + } + } + + /** + * Renders the openning tag for the datagrid control which will render table caption if present. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + parent::renderBeginTag($writer); + if(($caption=$this->getCaption())!=='') + { + if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet) + $writer->addAttribute('align',strtolower($align)); + $writer->renderBeginTag('caption'); + $writer->write($caption); + $writer->renderEndTag(); + } + } + + /** + * Renders the datagrid. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->getHasControls()) + { + $this->groupCells(); + if($this->_useEmptyTemplate) + { + $control=new TWebControl; + $control->setID($this->getClientID()); + $control->copyBaseAttributes($this); + if($this->getHasStyle()) + $control->getStyle()->copyFrom($this->getStyle()); + $control->renderBeginTag($writer); + $this->renderContents($writer); + $control->renderEndTag($writer); + } + else if($this->getViewState('ItemCount',0)>0) + { + $this->applyItemStyles(); + if($this->_topPager) + { + $this->_topPager->renderControl($writer); + $writer->writeLine(); + } + $this->renderTable($writer); + if($this->_bottomPager) + { + $writer->writeLine(); + $this->_bottomPager->renderControl($writer); + } + } + } + } + + /** + * Renders the tabular data. + * @param THtmlWriter writer + */ + protected function renderTable($writer) + { + $this->renderBeginTag($writer); + if($this->_header && $this->_header->getVisible()) + { + $writer->writeLine(); + if($style=$this->getViewState('TableHeadStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('thead'); + $this->_header->render($writer); + $writer->renderEndTag(); + } + $writer->writeLine(); + if($style=$this->getViewState('TableBodyStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('tbody'); + foreach($this->getItems() as $item) + $item->renderControl($writer); + $writer->renderEndTag(); + + if($this->_footer && $this->_footer->getVisible()) + { + $writer->writeLine(); + if($style=$this->getViewState('TableFootStyle',null)) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('tfoot'); + $this->_footer->render($writer); + $writer->renderEndTag(); + } + + $writer->writeLine(); + $this->renderEndTag($writer); + } +} + +/** + * TDataGridItemEventParameter class + * + * TDataGridItemEventParameter encapsulates the parameter data for + * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls. + * The {@link getItem Item} property indicates the datagrid item related with the event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItemEventParameter extends TEventParameter +{ + /** + * The TDataGridItem control responsible for the event. + * @var TDataGridItem + */ + private $_item=null; + + /** + * Constructor. + * @param TDataGridItem datagrid item related with the corresponding event + */ + public function __construct(TDataGridItem $item) + { + $this->_item=$item; + } + + /** + * @return TDataGridItem datagrid item related with the corresponding event + */ + public function getItem() + { + return $this->_item; + } +} + +/** + * TDataGridPagerEventParameter class + * + * TDataGridPagerEventParameter encapsulates the parameter data for + * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls. + * The {@link getPager Pager} property indicates the datagrid pager related with the event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPagerEventParameter extends TEventParameter +{ + /** + * The TDataGridPager control responsible for the event. + * @var TDataGridPager + */ + protected $_pager=null; + + /** + * Constructor. + * @param TDataGridPager datagrid pager related with the corresponding event + */ + public function __construct(TDataGridPager $pager) + { + $this->_pager=$pager; + } + + /** + * @return TDataGridPager datagrid pager related with the corresponding event + */ + public function getPager() + { + return $this->_pager; + } +} + +/** + * TDataGridCommandEventParameter class + * + * TDataGridCommandEventParameter encapsulates the parameter data for + * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls. + * + * The {@link getItem Item} property indicates the datagrid item related with the event. + * The {@link getCommandSource CommandSource} refers to the control that originally + * raises the Command event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridCommandEventParameter extends TCommandEventParameter +{ + /** + * @var TDataGridItem the TDataGridItem control responsible for the event. + */ + private $_item=null; + /** + * @var TControl the control originally raises the <b>Command</b> event. + */ + private $_source=null; + + /** + * Constructor. + * @param TDataGridItem datagrid item responsible for the event + * @param TControl original event sender + * @param TCommandEventParameter original event parameter + */ + public function __construct($item,$source,TCommandEventParameter $param) + { + $this->_item=$item; + $this->_source=$source; + parent::__construct($param->getCommandName(),$param->getCommandParameter()); + } + + /** + * @return TDataGridItem the TDataGridItem control responsible for the event. + */ + public function getItem() + { + return $this->_item; + } + + /** + * @return TControl the control originally raises the <b>Command</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } +} + +/** + * TDataGridSortCommandEventParameter class + * + * TDataGridSortCommandEventParameter encapsulates the parameter data for + * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls. + * + * The {@link getCommandSource CommandSource} property refers to the control + * that originally raises the OnCommand event, while {@link getSortExpression SortExpression} + * gives the sort expression carried with the sort command. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridSortCommandEventParameter extends TEventParameter +{ + /** + * @var string sort expression + */ + private $_sortExpression=''; + /** + * @var TControl original event sender + */ + private $_source=null; + + /** + * Constructor. + * @param TControl the control originally raises the <b>OnCommand</b> event. + * @param TDataGridCommandEventParameter command event parameter + */ + public function __construct($source,TDataGridCommandEventParameter $param) + { + $this->_source=$source; + $this->_sortExpression=$param->getCommandParameter(); + } + + /** + * @return TControl the control originally raises the <b>OnCommand</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } + + /** + * @return string sort expression + */ + public function getSortExpression() + { + return $this->_sortExpression; + } +} + +/** + * TDataGridPageChangedEventParameter class + * + * TDataGridPageChangedEventParameter encapsulates the parameter data for + * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls. + * + * The {@link getCommandSource CommandSource} property refers to the control + * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex} + * returns the new page index carried with the page command. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPageChangedEventParameter extends TEventParameter +{ + /** + * @var integer new page index + */ + private $_newIndex; + /** + * @var TControl original event sender + */ + private $_source=null; + + /** + * Constructor. + * @param TControl the control originally raises the <b>OnCommand</b> event. + * @param integer new page index + */ + public function __construct($source,$newPageIndex) + { + $this->_source=$source; + $this->_newIndex=$newPageIndex; + } + + /** + * @return TControl the control originally raises the <b>OnCommand</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } + + /** + * @return integer new page index + */ + public function getNewPageIndex() + { + return $this->_newIndex; + } +} + +/** + * TDataGridItem class + * + * A TDataGridItem control represents an item in the {@link TDataGrid} control, + * such as heading section, footer section, or a data item. + * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> + * and {@link getDataItem DataItem} properties, respectively. The type of the item + * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex} + * gives the index of the item from the bound data source. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItem extends TTableRow implements INamingContainer +{ + /** + * @var integer index of the data item in the Items collection of datagrid + */ + private $_itemIndex=''; + /** + * @var integer index of the item from the bound data source + */ + private $_dataSourceIndex=0; + /** + * type of the TDataGridItem + * @var string + */ + private $_itemType=''; + /** + * value of the data item + * @var mixed + */ + private $_data=null; + + /** + * Constructor. + * @param integer zero-based index of the item in the item collection of datagrid + * @param TListItemType item type + */ + public function __construct($itemIndex,$dataSourceIndex,$itemType) + { + $this->_itemIndex=$itemIndex; + $this->_dataSourceIndex=$dataSourceIndex; + $this->setItemType($itemType); + if($itemType===TListItemType::Header) + $this->setTableSection(TTableRowSection::Header); + else if($itemType===TListItemType::Footer) + $this->setTableSection(TTableRowSection::Footer); + } + + /** + * @return TListItemType item type. + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * @return integer zero-based index of the item in the item collection of datagrid + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * @return integer the index of the datagrid item from the bound data source + */ + public function getDataSourceIndex() + { + return $this->_dataSourceIndex; + } + + /** + * @return mixed data associated with the item + * @since 3.1.0 + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + * @since 3.1.0 + */ + public function setData($value) + { + $this->_data=$value; + } + + /** + * This property is deprecated since v3.1.0. + * @return mixed data associated with the item + * @deprecated deprecated since v3.1.0. Use {@link getData} instead. + */ + public function getDataItem() + { + return $this->getData(); + } + + /** + * This property is deprecated since v3.1.0. + * @param mixed data to be associated with the item + * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. + */ + public function setDataItem($value) + { + return $this->setData($value); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + + +/** + * TDataGridPager class. + * + * TDataGridPager represents a datagrid pager. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPager extends TPanel implements INamingContainer +{ + private $_dataGrid; + + /** + * Constructor. + * @param TDataGrid datagrid object + */ + public function __construct($dataGrid) + { + $this->_dataGrid=$dataGrid; + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } + + /** + * @return TDataGrid the datagrid owning this pager + */ + public function getDataGrid() + { + return $this->_dataGrid; + } + + /** + * @return string item type. + */ + public function getItemType() + { + return TListItemType::Pager; + } +} + + +/** + * TDataGridItemCollection class. + * + * TDataGridItemCollection represents a collection of data grid items. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridItemCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only TDataGridItem. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem. + */ + public function insertAt($index,$item) + { + if($item instanceof TDataGridItem) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required'); + } +} + +/** + * TDataGridColumnCollection class. + * + * TDataGridColumnCollection represents a collection of data grid columns. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridColumnCollection extends TList +{ + /** + * the control that owns this collection. + * @var TControl + */ + private $_o; + + /** + * Constructor. + * @param TDataGrid the control that owns this collection. + */ + public function __construct(TDataGrid $owner) + { + $this->_o=$owner; + } + + /** + * @return TDataGrid 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 inserting only TDataGridColumn. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn. + */ + public function insertAt($index,$item) + { + if($item instanceof TDataGridColumn) + { + $item->setOwner($this->_o); + parent::insertAt($index,$item); + } + else + throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required'); + } +} + +/** + * TDataGridPagerMode class. + * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take. + * + * The following enumerable values are defined: + * - NextPrev: pager buttons are displayed as next and previous pages + * - Numeric: pager buttons are displayed as numeric page numbers + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerMode extends TEnumerable +{ + const NextPrev='NextPrev'; + const Numeric='Numeric'; +} + + +/** + * TDataGridPagerButtonType class. + * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons. + * + * The following enumerable values are defined: + * - LinkButton: link buttons + * - PushButton: form submit buttons + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerButtonType extends TEnumerable +{ + const LinkButton='LinkButton'; + const PushButton='PushButton'; +} + + +/** + * TDataGridPagerPosition class. + * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at. + * + * The following enumerable values are defined: + * - Bottom: pager appears only at the bottom of the data grid. + * - Top: pager appears only at the top of the data grid. + * - TopAndBottom: pager appears on both top and bottom of the data grid. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDataGridPagerPosition extends TEnumerable +{ + const Bottom='Bottom'; + const Top='Top'; + const TopAndBottom='TopAndBottom'; +} + diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php index d37fbc40..4794fbf8 100644 --- a/framework/Web/UI/WebControls/TDataGridColumn.php +++ b/framework/Web/UI/WebControls/TDataGridColumn.php @@ -1,567 +1,567 @@ -<?php
-/**
- * TDataGridColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Util.TDataFieldAccessor');
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridColumn class
- *
- * TDataGridColumn serves as the base class for the different column types of
- * the {@link TDataGrid} control.
- * TDataGridColumn defines the properties and methods that are common among
- * all datagrid column types. In particular, it initializes header and footer
- * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
- * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
- * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
- * will be displayed instead in the header cell.
- * The {@link getItemStyle ItemStyle} is applied to cells that belong to
- * non-header and -footer datagrid items.
- *
- * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
- * is not empty, the header cell will display a button (linkbutton or imagebutton)
- * that will bubble the sort command event to the datagrid.
- *
- * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
- * and {@link setFooterRenderer FooterRenderer} which can be used to specify
- * the layout of header and footer column cells.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
- * If a column has this property set true, consecutive cells having the same content in this
- * column will be grouped into one cell.
- * Note, there are some limitations to cell grouping. We determine the cell content according to
- * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
- * some child controls, we will pick up the first control who implements {@link IDataRenderer}
- * and obtain its {@link IDataRenderer::getData Data} property.
- *
- * The following datagrid column types are provided by the framework currently,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * To create your own column class, simply override {@link initializeCell()} method,
- * which is the major logic for managing the data and presentation of cells in the column.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataGridColumn extends TApplicationComponent
-{
- private $_id='';
- private $_owner=null;
- private $_viewState=array();
-
- /**
- * @return string the ID of the column.
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * Sets the ID of the column.
- * By explicitly specifying the column ID, one can access the column
- * by $templateControl->ColumnID.
- * @param string the ID of the column.
- * @throws TInvalidDataValueException if the ID is of bad format
- */
- public function setID($value)
- {
- if(!preg_match(TControl::ID_FORMAT,$value))
- throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
- $this->_id=$value;
- }
-
- /**
- * @return string the text to be displayed in the header of this column
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * @param string text to be displayed in the header of this column
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',$value,'');
- }
-
- /**
- * @return string the url of the image to be displayed in header
- */
- public function getHeaderImageUrl()
- {
- return $this->getViewState('HeaderImageUrl','');
- }
-
- /**
- * @param string the url of the image to be displayed in header
- */
- public function setHeaderImageUrl($value)
- {
- $this->setViewState('HeaderImageUrl',$value,'');
- }
-
- /**
- * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the column header cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column header cell.
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle($createStyle=true)
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the text to be displayed in the footer of this column
- */
- public function getFooterText()
- {
- return $this->getViewState('FooterText','');
- }
-
- /**
- * @param string text to be displayed in the footer of this column
- */
- public function setFooterText($value)
- {
- $this->setViewState('FooterText',$value,'');
- }
-
- /**
- * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the column footer cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column footer cell.
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle($createStyle=true)
- {
- if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle($createStyle=true)
- {
- if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the name of the field or expression for sorting
- */
- public function getSortExpression()
- {
- return $this->getViewState('SortExpression','');
- }
-
- /**
- * @param string the name of the field or expression for sorting
- */
- public function setSortExpression($value)
- {
- $this->setViewState('SortExpression',$value,'');
- }
-
- /**
- * @return boolean whether cells having the same content should be grouped together. Defaults to false.
- * @since 3.1.1
- */
- public function getEnableCellGrouping()
- {
- return $this->getViewState('EnableCellGrouping',false);
- }
-
- /**
- * @param boolean whether cells having the same content should be grouped together.
- * @since 3.1.1
- */
- public function setEnableCellGrouping($value)
- {
- $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the column is visible. Defaults to true.
- */
- public function getVisible($checkParents=true)
- {
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the column is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a viewstate value.
- *
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- protected function getViewState($key,$defaultValue=null)
- {
- return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- protected function setViewState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_viewState[$key]);
- else
- $this->_viewState[$key]=$value;
- }
-
- /**
- * Loads persistent state values.
- * @param mixed state values
- */
- public function loadState($state)
- {
- $this->_viewState=$state;
- }
-
- /**
- * Saves persistent state values.
- * @return mixed values to be saved
- */
- public function saveState()
- {
- return $this->_viewState;
- }
-
- /**
- * @return TDataGrid datagrid that owns this column
- */
- public function getOwner()
- {
- return $this->_owner;
- }
-
- /**
- * @param TDataGrid datagrid object that owns this column
- */
- public function setOwner(TDataGrid $value)
- {
- $this->_owner=$value;
- }
-
- /**
- * Initializes the column.
- * This method is invoked by {@link TDataGrid} when the column
- * is about to be used to initialize datagrid items.
- * Derived classes may override this method to do additional initialization.
- */
- public function initialize()
- {
- }
-
- /**
- * Fetches the value of the data at the specified field.
- * If the data is an array, the field is used as an array key.
- * If the data is an of {@link TMap}, {@link TList} or their derived class,
- * the field is used as a key value.
- * If the data is a component, the field is used as the name of a property.
- * @param mixed data containing the field of value
- * @param string the data field
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data or the field is invalid.
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-
-
- /**
- * Initializes the specified cell to its initial values.
- * The default implementation sets the content of header and footer cells.
- * If sorting is enabled by the grid and sort expression is specified in the column,
- * the header cell will show a link/image button. Otherwise, the header/footer cell
- * will only show static text/image.
- * This method can be overriden to provide customized intialization to column cells.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Header)
- $this->initializeHeaderCell($cell,$columnIndex);
- else if($itemType===TListItemType::Footer)
- $this->initializeFooterCell($cell,$columnIndex);
- }
-
- /**
- * Returns a value indicating whether this column allows sorting.
- * The column allows sorting only when {@link getSortExpression SortExpression}
- * is not empty and the datagrid allows sorting.
- * @return boolean whether this column allows sorting
- */
- public function getAllowSorting()
- {
- return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
- }
-
- /**
- * Initializes the header cell.
- *
- * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
- * instantiate the header cell. If that is not available, it will populate
- * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
- * and {@link getHeaderText HeaderText} property values.
- *
- * If the column allows sorting, image or text will be created as
- * a button which issues <b>Sort</b> command upon user click.
- *
- * @param TTableCell the cell to be initialized
- * @param integer the index to the Columns property that the cell resides in.
- */
- protected function initializeHeaderCell($cell,$columnIndex)
- {
- $text=$this->getHeaderText();
-
- if(($classPath=$this->getHeaderRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IDataRenderer)
- {
- if($control instanceof IItemDataRenderer)
- {
- $item=$cell->getParent();
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $control->setData($text);
- }
- }
- else if($this->getAllowSorting())
- {
- $sortExpression=$this->getSortExpression();
- if(($url=$this->getHeaderImageUrl())!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- $button->setImageUrl($url);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- if($text!=='')
- $button->setAlternateText($text);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else if($text!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- $button->setText($text);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else
- $cell->setText(' ');
- }
- else
- {
- if(($url=$this->getHeaderImageUrl())!=='')
- {
- $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
- $image->setImageUrl($url);
- if($text!=='')
- $image->setAlternateText($text);
- $cell->getControls()->add($image);
- }
- else if($text!=='')
- $cell->setText($text);
- else
- $cell->setText(' ');
- }
- }
-
- /**
- * Initializes the footer cell.
- *
- * This method attempts to use {@link getFooterRenderer FooterRenderer} to
- * instantiate the footer cell. If that is not available, it will populate
- * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl}
- *
- * @param TTableCell the cell to be initialized
- * @param integer the index to the Columns property that the cell resides in.
- */
- protected function initializeFooterCell($cell,$columnIndex)
- {
- $text=$this->getFooterText();
- if(($classPath=$this->getFooterRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IDataRenderer)
- {
- if($control instanceof IItemDataRenderer)
- {
- $item=$cell->getParent();
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $control->setData($text);
- }
- }
- else if($text!=='')
- $cell->setText($text);
- else
- $cell->setText(' ');
- }
-
- /**
- * Formats the text value according to a format string.
- * If the format string is empty, the original value is converted into
- * a string and returned.
- * If the format string starts with '#', the string is treated as a PHP expression
- * within which the token '{0}' is translated with the data value to be formated.
- * Otherwise, the format string and the data value are passed
- * as the first and second parameters in {@link sprintf}.
- * @param string format string
- * @param mixed the data to be formatted
- * @return string the formatted result
- */
- protected function formatDataValue($formatString,$value)
- {
- if($formatString==='')
- return TPropertyValue::ensureString($value);
- else if($formatString[0]==='#')
- {
- $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
- try
- {
- if(eval("\$result=$expression;")===false)
- throw new Exception('');
- return $result;
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
- }
- }
- else
- return sprintf($formatString,$value);
- }
-}
-
-
-/**
- * TButtonColumnType class.
- * TButtonColumnType defines the enumerable type for the possible types of buttons
- * that can be used in a {@link TButtonColumn}.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form buttons
- * - ImageButton: image buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TButtonColumnType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
- const ImageButton='ImageButton';
-}
-
+<?php +/** + * TDataGridColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Util.TDataFieldAccessor'); +Prado::using('System.Web.UI.WebControls.TDataGrid'); + +/** + * TDataGridColumn class + * + * TDataGridColumn serves as the base class for the different column types of + * the {@link TDataGrid} control. + * TDataGridColumn defines the properties and methods that are common among + * all datagrid column types. In particular, it initializes header and footer + * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle} + * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties. + * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image + * will be displayed instead in the header cell. + * The {@link getItemStyle ItemStyle} is applied to cells that belong to + * non-header and -footer datagrid items. + * + * When the datagrid enables sorting, if the {@link setSortExpression SortExpression} + * is not empty, the header cell will display a button (linkbutton or imagebutton) + * that will bubble the sort command event to the datagrid. + * + * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer} + * and {@link setFooterRenderer FooterRenderer} which can be used to specify + * the layout of header and footer column cells. + * A renderer refers to a control class that is to be instantiated as a control. + * For more details, see {@link TRepeater} and {@link TDataList}. + * + * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}. + * If a column has this property set true, consecutive cells having the same content in this + * column will be grouped into one cell. + * Note, there are some limitations to cell grouping. We determine the cell content according to + * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has + * some child controls, we will pick up the first control who implements {@link IDataRenderer} + * and obtain its {@link IDataRenderer::getData Data} property. + * + * The following datagrid column types are provided by the framework currently, + * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data. + * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons + * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state + * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource. + * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource. + * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource. + * - {@link TTemplateColumn}, displaying content based on templates. + * + * To create your own column class, simply override {@link initializeCell()} method, + * which is the major logic for managing the data and presentation of cells in the column. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataGridColumn extends TApplicationComponent +{ + private $_id=''; + private $_owner=null; + private $_viewState=array(); + + /** + * @return string the ID of the column. + */ + public function getID() + { + return $this->_id; + } + + /** + * Sets the ID of the column. + * By explicitly specifying the column ID, one can access the column + * by $templateControl->ColumnID. + * @param string the ID of the column. + * @throws TInvalidDataValueException if the ID is of bad format + */ + public function setID($value) + { + if(!preg_match(TControl::ID_FORMAT,$value)) + throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value); + $this->_id=$value; + } + + /** + * @return string the text to be displayed in the header of this column + */ + public function getHeaderText() + { + return $this->getViewState('HeaderText',''); + } + + /** + * @param string text to be displayed in the header of this column + */ + public function setHeaderText($value) + { + $this->setViewState('HeaderText',$value,''); + } + + /** + * @return string the url of the image to be displayed in header + */ + public function getHeaderImageUrl() + { + return $this->getViewState('HeaderImageUrl',''); + } + + /** + * @param string the url of the image to be displayed in header + */ + public function setHeaderImageUrl($value) + { + $this->setViewState('HeaderImageUrl',$value,''); + } + + /** + * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getHeaderRenderer() + { + return $this->getViewState('HeaderRenderer',''); + } + + /** + * Sets the column header cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the column header cell. + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the {@link getFooterText FooterText}. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setHeaderRenderer($value) + { + $this->setViewState('HeaderRenderer',$value,''); + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle($createStyle=true) + { + if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return string the text to be displayed in the footer of this column + */ + public function getFooterText() + { + return $this->getViewState('FooterText',''); + } + + /** + * @param string text to be displayed in the footer of this column + */ + public function setFooterText($value) + { + $this->setViewState('FooterText',$value,''); + } + + /** + * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getFooterRenderer() + { + return $this->getViewState('FooterRenderer',''); + } + + /** + * Sets the column footer cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the column footer cell. + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the {@link getFooterText FooterText}. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setFooterRenderer($value) + { + $this->setViewState('FooterRenderer',$value,''); + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle($createStyle=true) + { + if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @param boolean whether to create a style if previously not existing + * @return TTableItemStyle the style for item + */ + public function getItemStyle($createStyle=true) + { + if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return string the name of the field or expression for sorting + */ + public function getSortExpression() + { + return $this->getViewState('SortExpression',''); + } + + /** + * @param string the name of the field or expression for sorting + */ + public function setSortExpression($value) + { + $this->setViewState('SortExpression',$value,''); + } + + /** + * @return boolean whether cells having the same content should be grouped together. Defaults to false. + * @since 3.1.1 + */ + public function getEnableCellGrouping() + { + return $this->getViewState('EnableCellGrouping',false); + } + + /** + * @param boolean whether cells having the same content should be grouped together. + * @since 3.1.1 + */ + public function setEnableCellGrouping($value) + { + $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether the column is visible. Defaults to true. + */ + public function getVisible($checkParents=true) + { + return $this->getViewState('Visible',true); + } + + /** + * @param boolean whether the column is visible + */ + public function setVisible($value) + { + $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Returns a viewstate value. + * + * @param string the name of the viewstate value to be returned + * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned + * @return mixed the viewstate value corresponding to $key + */ + protected function getViewState($key,$defaultValue=null) + { + return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue; + } + + /** + * Sets a viewstate value. + * + * Make sure that the viewstate value must be serializable and unserializable. + * @param string the name of the viewstate value + * @param mixed the viewstate value to be set + * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate. + */ + protected function setViewState($key,$value,$defaultValue=null) + { + if($value===$defaultValue) + unset($this->_viewState[$key]); + else + $this->_viewState[$key]=$value; + } + + /** + * Loads persistent state values. + * @param mixed state values + */ + public function loadState($state) + { + $this->_viewState=$state; + } + + /** + * Saves persistent state values. + * @return mixed values to be saved + */ + public function saveState() + { + return $this->_viewState; + } + + /** + * @return TDataGrid datagrid that owns this column + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * @param TDataGrid datagrid object that owns this column + */ + public function setOwner(TDataGrid $value) + { + $this->_owner=$value; + } + + /** + * Initializes the column. + * This method is invoked by {@link TDataGrid} when the column + * is about to be used to initialize datagrid items. + * Derived classes may override this method to do additional initialization. + */ + public function initialize() + { + } + + /** + * Fetches the value of the data at the specified field. + * If the data is an array, the field is used as an array key. + * If the data is an of {@link TMap}, {@link TList} or their derived class, + * the field is used as a key value. + * If the data is a component, the field is used as the name of a property. + * @param mixed data containing the field of value + * @param string the data field + * @return mixed data value at the specified field + * @throws TInvalidDataValueException if the data or the field is invalid. + */ + protected function getDataFieldValue($data,$field) + { + return TDataFieldAccessor::getDataFieldValue($data,$field); + } + + + /** + * Initializes the specified cell to its initial values. + * The default implementation sets the content of header and footer cells. + * If sorting is enabled by the grid and sort expression is specified in the column, + * the header cell will show a link/image button. Otherwise, the header/footer cell + * will only show static text/image. + * This method can be overriden to provide customized intialization to column cells. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Header) + $this->initializeHeaderCell($cell,$columnIndex); + else if($itemType===TListItemType::Footer) + $this->initializeFooterCell($cell,$columnIndex); + } + + /** + * Returns a value indicating whether this column allows sorting. + * The column allows sorting only when {@link getSortExpression SortExpression} + * is not empty and the datagrid allows sorting. + * @return boolean whether this column allows sorting + */ + public function getAllowSorting() + { + return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting()); + } + + /** + * Initializes the header cell. + * + * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to + * instantiate the header cell. If that is not available, it will populate + * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl} + * and {@link getHeaderText HeaderText} property values. + * + * If the column allows sorting, image or text will be created as + * a button which issues <b>Sort</b> command upon user click. + * + * @param TTableCell the cell to be initialized + * @param integer the index to the Columns property that the cell resides in. + */ + protected function initializeHeaderCell($cell,$columnIndex) + { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + } + else if($this->getAllowSorting()) + { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); + $button->setImageUrl($url); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + if($text!=='') + $button->setAlternateText($text); + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else if($text!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); + $button->setText($text); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else + $cell->setText(' '); + } + else + { + if(($url=$this->getHeaderImageUrl())!=='') + { + $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } + + /** + * Initializes the footer cell. + * + * This method attempts to use {@link getFooterRenderer FooterRenderer} to + * instantiate the footer cell. If that is not available, it will populate + * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl} + * + * @param TTableCell the cell to be initialized + * @param integer the index to the Columns property that the cell resides in. + */ + protected function initializeFooterCell($cell,$columnIndex) + { + $text=$this->getFooterText(); + if(($classPath=$this->getFooterRenderer())!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + + /** + * Formats the text value according to a format string. + * If the format string is empty, the original value is converted into + * a string and returned. + * If the format string starts with '#', the string is treated as a PHP expression + * within which the token '{0}' is translated with the data value to be formated. + * Otherwise, the format string and the data value are passed + * as the first and second parameters in {@link sprintf}. + * @param string format string + * @param mixed the data to be formatted + * @return string the formatted result + */ + protected function formatDataValue($formatString,$value) + { + if($formatString==='') + return TPropertyValue::ensureString($value); + else if($formatString[0]==='#') + { + $expression=strtr(substr($formatString,1),array('{0}'=>'$value')); + try + { + if(eval("\$result=$expression;")===false) + throw new Exception(''); + return $result; + } + catch(Exception $e) + { + throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage()); + } + } + else + return sprintf($formatString,$value); + } +} + + +/** + * TButtonColumnType class. + * TButtonColumnType defines the enumerable type for the possible types of buttons + * that can be used in a {@link TButtonColumn}. + * + * The following enumerable values are defined: + * - LinkButton: link buttons + * - PushButton: form buttons + * - ImageButton: image buttons + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TButtonColumnType extends TEnumerable +{ + const LinkButton='LinkButton'; + const PushButton='PushButton'; + const ImageButton='ImageButton'; +} + diff --git a/framework/Web/UI/WebControls/TDataGridItemRenderer.php b/framework/Web/UI/WebControls/TDataGridItemRenderer.php index 0e30a062..dbbbec11 100644 --- a/framework/Web/UI/WebControls/TDataGridItemRenderer.php +++ b/framework/Web/UI/WebControls/TDataGridItemRenderer.php @@ -1,30 +1,30 @@ -<?php
-/**
- * TDataGridItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataGridItemRenderer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataGridItemRenderer class
- *
- * TDataGridItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataGrid}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataGridItemRenderer extends TItemDataRenderer
-{
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGrid'); +Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); + +/** + * TDataGridItemRenderer class + * + * TDataGridItemRenderer can be used as a convenient base class to + * define an item renderer class specific for {@link TDataGrid}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +class TDataGridItemRenderer extends TItemDataRenderer +{ +} + diff --git a/framework/Web/UI/WebControls/TDataGridPagerStyle.php b/framework/Web/UI/WebControls/TDataGridPagerStyle.php index 12346c06..2464291a 100644 --- a/framework/Web/UI/WebControls/TDataGridPagerStyle.php +++ b/framework/Web/UI/WebControls/TDataGridPagerStyle.php @@ -1,255 +1,255 @@ -<?php
-/**
- * TDataGridPagerStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridPagerStyle class.
- *
- * TDataGridPagerStyle specifies the styles available for a datagrid pager.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerStyle extends TPanelStyle
-{
- private $_mode=null;
- private $_nextText=null;
- private $_prevText=null;
- private $_firstText=null;
- private $_lastText=null;
- private $_buttonCount=null;
- private $_position=null;
- private $_visible=null;
- private $_buttonType=null;
-
- /**
- * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
- */
- public function getMode()
- {
- return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
- }
-
- /**
- * @param TDataGridPagerMode pager mode.
- */
- public function setMode($value)
- {
- $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
- }
-
- /**
- * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
- }
-
- /**
- * @param TDataGridPagerButtonType the type of command button
- */
- public function setButtonType($value)
- {
- $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
- }
-
- /**
- * @return string text for the next page button. Defaults to '>'.
- */
- public function getNextPageText()
- {
- return $this->_nextText===null?'>':$this->_nextText;
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setNextPageText($value)
- {
- $this->_nextText=$value;
- }
-
- /**
- * @return string text for the previous page button. Defaults to '<'.
- */
- public function getPrevPageText()
- {
- return $this->_prevText===null?'<':$this->_prevText;
- }
-
- /**
- * @param string text for the previous page button.
- */
- public function setPrevPageText($value)
- {
- $this->_prevText=$value;
- }
-
- /**
- * @return string text for the first page button. Defaults to '<<'.
- */
- public function getFirstPageText()
- {
- return $this->_firstText===null?'<<':$this->_firstText;
- }
-
- /**
- * @param string text for the first page button.
- */
- public function setFirstPageText($value)
- {
- $this->_firstText=$value;
- }
-
- /**
- * @return string text for the last page button. Defaults to '>>'.
- */
- public function getLastPageText()
- {
- return $this->_lastText===null?'>>':$this->_lastText;
- }
-
- /**
- * @param string text for the last page button.
- */
- public function setLastPageText($value)
- {
- $this->_lastText=$value;
- }
-
- /**
- * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
- */
- public function getPageButtonCount()
- {
- return $this->_buttonCount===null?10:$this->_buttonCount;
- }
-
- /**
- * @param integer maximum number of pager buttons to be displayed
- * @throws TInvalidDataValueException if the value is less than 1.
- */
- public function setPageButtonCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
- $this->_buttonCount=$value;
- }
-
- /**
- * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
- */
- public function getPosition()
- {
- return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
- }
-
- /**
- * @param TDataGridPagerPosition where the pager is to be displayed.
- */
- public function setPosition($value)
- {
- $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
- }
-
- /**
- * @return boolean whether the pager is visible. Defaults to true.
- */
- public function getVisible()
- {
- return $this->_visible===null?true:$this->_visible;
- }
-
- /**
- * @param boolean whether the pager is visible.
- */
- public function setVisible($value)
- {
- $this->_visible=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Resets the style to the original empty state.
- */
- public function reset()
- {
- parent::reset();
- $this->_visible=null;
- $this->_position=null;
- $this->_buttonCount=null;
- $this->_prevText=null;
- $this->_nextText=null;
- $this->_mode=null;
- $this->_buttonType=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($style->_visible!==null)
- $this->_visible=$style->_visible;
- if($style->_position!==null)
- $this->_position=$style->_position;
- if($style->_buttonCount!==null)
- $this->_buttonCount=$style->_buttonCount;
- if($style->_prevText!==null)
- $this->_prevText=$style->_prevText;
- if($style->_nextText!==null)
- $this->_nextText=$style->_nextText;
- if($style->_mode!==null)
- $this->_mode=$style->_mode;
- if($style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($this->_visible===null)
- $this->_visible=$style->_visible;
- if($this->_position===null)
- $this->_position=$style->_position;
- if($this->_buttonCount===null)
- $this->_buttonCount=$style->_buttonCount;
- if($this->_prevText===null)
- $this->_prevText=$style->_prevText;
- if($this->_nextText===null)
- $this->_nextText=$style->_nextText;
- if($this->_mode===null)
- $this->_mode=$style->_mode;
- if($this->_buttonType===null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-}
-
+<?php +/** + * TDataGridPagerStyle class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGrid'); + +/** + * TDataGridPagerStyle class. + * + * TDataGridPagerStyle specifies the styles available for a datagrid pager. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataGridPagerStyle extends TPanelStyle +{ + private $_mode=null; + private $_nextText=null; + private $_prevText=null; + private $_firstText=null; + private $_lastText=null; + private $_buttonCount=null; + private $_position=null; + private $_visible=null; + private $_buttonType=null; + + /** + * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev. + */ + public function getMode() + { + return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode; + } + + /** + * @param TDataGridPagerMode pager mode. + */ + public function setMode($value) + { + $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode'); + } + + /** + * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton. + */ + public function getButtonType() + { + return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType; + } + + /** + * @param TDataGridPagerButtonType the type of command button + */ + public function setButtonType($value) + { + $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType'); + } + + /** + * @return string text for the next page button. Defaults to '>'. + */ + public function getNextPageText() + { + return $this->_nextText===null?'>':$this->_nextText; + } + + /** + * @param string text for the next page button. + */ + public function setNextPageText($value) + { + $this->_nextText=$value; + } + + /** + * @return string text for the previous page button. Defaults to '<'. + */ + public function getPrevPageText() + { + return $this->_prevText===null?'<':$this->_prevText; + } + + /** + * @param string text for the previous page button. + */ + public function setPrevPageText($value) + { + $this->_prevText=$value; + } + + /** + * @return string text for the first page button. Defaults to '<<'. + */ + public function getFirstPageText() + { + return $this->_firstText===null?'<<':$this->_firstText; + } + + /** + * @param string text for the first page button. + */ + public function setFirstPageText($value) + { + $this->_firstText=$value; + } + + /** + * @return string text for the last page button. Defaults to '>>'. + */ + public function getLastPageText() + { + return $this->_lastText===null?'>>':$this->_lastText; + } + + /** + * @param string text for the last page button. + */ + public function setLastPageText($value) + { + $this->_lastText=$value; + } + + /** + * @return integer maximum number of pager buttons to be displayed. Defaults to 10. + */ + public function getPageButtonCount() + { + return $this->_buttonCount===null?10:$this->_buttonCount; + } + + /** + * @param integer maximum number of pager buttons to be displayed + * @throws TInvalidDataValueException if the value is less than 1. + */ + public function setPageButtonCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<1) + throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid'); + $this->_buttonCount=$value; + } + + /** + * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom. + */ + public function getPosition() + { + return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position; + } + + /** + * @param TDataGridPagerPosition where the pager is to be displayed. + */ + public function setPosition($value) + { + $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition'); + } + + /** + * @return boolean whether the pager is visible. Defaults to true. + */ + public function getVisible() + { + return $this->_visible===null?true:$this->_visible; + } + + /** + * @param boolean whether the pager is visible. + */ + public function setVisible($value) + { + $this->_visible=TPropertyValue::ensureBoolean($value); + } + + /** + * Resets the style to the original empty state. + */ + public function reset() + { + parent::reset(); + $this->_visible=null; + $this->_position=null; + $this->_buttonCount=null; + $this->_prevText=null; + $this->_nextText=null; + $this->_mode=null; + $this->_buttonType=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TDataGridPagerStyle) + { + if($style->_visible!==null) + $this->_visible=$style->_visible; + if($style->_position!==null) + $this->_position=$style->_position; + if($style->_buttonCount!==null) + $this->_buttonCount=$style->_buttonCount; + if($style->_prevText!==null) + $this->_prevText=$style->_prevText; + if($style->_nextText!==null) + $this->_nextText=$style->_nextText; + if($style->_mode!==null) + $this->_mode=$style->_mode; + if($style->_buttonType!==null) + $this->_buttonType=$style->_buttonType; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TDataGridPagerStyle) + { + if($this->_visible===null) + $this->_visible=$style->_visible; + if($this->_position===null) + $this->_position=$style->_position; + if($this->_buttonCount===null) + $this->_buttonCount=$style->_buttonCount; + if($this->_prevText===null) + $this->_prevText=$style->_prevText; + if($this->_nextText===null) + $this->_nextText=$style->_nextText; + if($this->_mode===null) + $this->_mode=$style->_mode; + if($this->_buttonType===null) + $this->_buttonType=$style->_buttonType; + } + } +} + diff --git a/framework/Web/UI/WebControls/TDataList.php b/framework/Web/UI/WebControls/TDataList.php index 43980c0c..49e9c749 100644 --- a/framework/Web/UI/WebControls/TDataList.php +++ b/framework/Web/UI/WebControls/TDataList.php @@ -1,1766 +1,1766 @@ -<?php
-/**
- * TDataList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataList class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseDataList class
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-/**
- * Includes TRepeatInfo class
- */
-Prado::using('System.Web.UI.WebControls.TRepeatInfo');
-
-/**
- * TDataList class
- *
- * TDataList represents a data bound and updatable list control.
- *
- * Like {@link TRepeater}, TDataList displays its content repeatedly based on
- * the data fetched from {@link setDataSource DataSource}.
- * The repeated contents in TDataList are called items, which are controls and
- * can be accessed through {@link getItems Items}. When {@link dataBind()} is
- * invoked, TDataList creates an item for each row of data and binds the data
- * row to the item. Optionally, a TDataList can have a header, a footer and/or
- * separators between items.
- *
- * TDataList differs from {@link TRepeater} in that it supports tiling the items
- * in different manners and it maintains status of items to handle data update.
- *
- * The layout of the repeated contents are specified by inline templates.
- * TDataList items, header, footer, etc. are being instantiated with the corresponding
- * templates when data is being bound to the repeater.
- *
- * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
- * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
- * as an external template (in fact, it can also be non-templated controls).
- *
- * A renderer can be any control class.
- * - If the class implements {@link IDataRenderer}, the <b>Data</b>
- * property will be set as the data row during databinding. Many PRADO controls
- * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
- * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
- * as the zero-based index of the item in the datalist item collection, and
- * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
- * {@link TDataListItemRenderer} may be used as the convenient base class which
- * already implements {@link IDataItemRenderer}.
- *
- * The following properties are used to specify different types of template and renderer
- * for a datalist:
- * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
- * for each repeated row of data
- * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
- * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
- * will be used instead.
- * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
- * for the datalist header.
- * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
- * for the datalist footer.
- * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
- * for content to be displayed between items.
- * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
- * used when data bound to the datalist is empty.
- * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
- * for the row being editted.
- * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
- * for the row being selected.
- *
- * If a content type is defined with both a template and a renderer, the latter takes precedence.
- *
- * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
- * - create item based on templates or renderers
- * - set the row of data to the item
- * - raise {@link onItemCreated OnItemCreated}:
- * - add the item as a child control
- * - call dataBind() of the item
- * - raise {@link onItemDataBound OnItemDataBound}:
- *
- * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
- * within some datalist item raises a <b>OnCommand</b> event. Therefore,
- * you can handle all sorts of <b>OnCommand</b> event in a central place by
- * writing an event handler for {@link onItemCommand OnItemCommand}.
- *
- * An additional event is raised if the <b>OnCommand</b> event has one of the following
- * command names:
- * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
- * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
- * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
- * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
- * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
- *
- * TDataList provides a few properties to support tiling the items.
- * The number of columns used to display the data items is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
- * which can take one of the following values:
- * - Table (default): items are organized using HTML table and cells.
- * When using this layout, one can set {@link setCellPadding CellPadding} and
- * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
- * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
- * to add a table caption with the specified alignment.
- * - Flow: items are organized using HTML spans and breaks.
- * - Raw: TDataList does not generate any HTML tags to do the tiling.
- *
- * Items in TDataList can be in one of the three status: normal browsing,
- * being editted and being selected. To change the status of a particular
- * item, set {@link setSelectedItemIndex SelectedItemIndex} or
- * {@link setEditItemIndex EditItemIndex}. The former will change
- * the indicated item to selected mode, which will cause the item to
- * use {@link setSelectedItemTemplate SelectedItemTemplate} or
- * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
- * The latter will change the indicated item to edit mode and to use corresponding
- * template or renderer.
- * Note, if an item is in edit mode, then selecting this item will have no effect.
- *
- * Different styles may be applied to items in different status. The style
- * application is performed in a hierarchical way: Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * - item's own style
- * - {@link getItemStyle ItemStyle}
- * - {@link getAlternatingItemStyle AlternatingItemStyle}
- * - {@link getSelectedItemStyle SelectedItemStyle}
- * - {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- *
- * When a page containing a datalist is post back, the datalist will restore automatically
- * all its contents, including items, header, footer and separators.
- * However, the data row associated with each item will not be recovered and become null.
- * To access the data, use one of the following ways:
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datalist item and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
- * Be aware though, if the size of your dataset is big, your page size will become big. Some
- * complex data may also have serializing problem if saved in viewstate.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
-{
- /**
- * Command name that TDataList understands. They are case-insensitive.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
-
- /**
- * @var TDataListItemCollection item list
- */
- private $_items=null;
- /**
- * @var Itemplate various item templates
- */
- private $_itemTemplate=null;
- private $_emptyTemplate=null;
- private $_alternatingItemTemplate=null;
- private $_selectedItemTemplate=null;
- private $_editItemTemplate=null;
- private $_headerTemplate=null;
- private $_footerTemplate=null;
- private $_separatorTemplate=null;
- /**
- * @var TControl header item
- */
- private $_header=null;
- /**
- * @var TControl footer item
- */
- private $_footer=null;
-
- /**
- * @return TDataListItemCollection item list
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataListItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * @return string the class name for datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist items.
- * This property takes precedence over {@link getItemTemplate ItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setItemTemplate
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getAlternatingItemRenderer()
- {
- return $this->getViewState('AlternatingItemRenderer','');
- }
-
- /**
- * Sets the alternative item renderer class.
- *
- * If not empty, the class will be used to instantiate as alternative datalist items.
- * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setAlternatingItemTemplate
- * @since 3.1.0
- */
- public function setAlternatingItemRenderer($value)
- {
- $this->setViewState('AlternatingItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being editted.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEditItemTemplate
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSelectedItemRenderer()
- {
- return $this->getViewState('SelectedItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being selected.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSelectedItemTemplate
- * @since 3.1.0
- */
- public function setSelectedItemRenderer($value)
- {
- $this->setViewState('SelectedItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSeparatorRenderer()
- {
- return $this->getViewState('SeparatorRenderer','');
- }
-
- /**
- * Sets the datalist item separator renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist item separators.
- * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSeparatorTemplate
- * @since 3.1.0
- */
- public function setSeparatorRenderer($value)
- {
- $this->setViewState('SeparatorRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist header item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the datalist header renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist header item.
- * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setHeaderTemplate
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the datalist footer renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist footer item.
- * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setFooterTemplate
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEmptyRenderer()
- {
- return $this->getViewState('EmptyRenderer','');
- }
-
- /**
- * Sets the datalist empty renderer class.
- *
- * The empty renderer is created as the child of the datalist
- * if data bound to the datalist is empty.
- * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEmptyTemplate
- * @since 3.1.0
- */
- public function setEmptyRenderer($value)
- {
- $this->setViewState('EmptyRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the template for item
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the template for item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the template for each alternating item
- */
- public function getAlternatingItemTemplate()
- {
- return $this->_alternatingItemTemplate;
- }
-
- /**
- * @param ITemplate the template for each alternating item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setAlternatingItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_alternatingItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the selected item template
- */
- public function getSelectedItemTemplate()
- {
- return $this->_selectedItemTemplate;
- }
-
- /**
- * @param ITemplate the selected item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSelectedItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_selectedItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the edit item template
- */
- public function getEditItemTemplate()
- {
- return $this->_editItemTemplate;
- }
-
- /**
- * @param ITemplate the edit item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEditItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_editItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datalist
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datalist
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
- }
-
- /**
- * @return ITemplate the separator template
- */
- public function getSeparatorTemplate()
- {
- return $this->_separatorTemplate;
- }
-
- /**
- * @param ITemplate the separator template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSeparatorTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_separatorTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for separator
- */
- public function getSeparatorStyle()
- {
- if(($style=$this->getViewState('SeparatorStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SeparatorStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TControl the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return mixed the key value of the currently selected item
- * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
- */
- public function getSelectedDataKey()
- {
- if($this->getDataKeyField()==='')
- throw new TInvalidOperationException('datalist_datakeyfield_required');
- $index=$this->getSelectedItemIndex();
- $dataKeys=$this->getDataKeys();
- if($index>=0 && $index<$dataKeys->getCount())
- return $dataKeys->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return TControl the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return boolean whether the header should be shown. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether to show header
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be shown. Defaults to true.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',true);
- }
-
- /**
- * @param boolean whether to show footer
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TRepeatInfo repeat information (primarily used by control developers)
- */
- protected function getRepeatInfo()
- {
- if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
- {
- $repeatInfo=new TRepeatInfo;
- $this->setViewState('RepeatInfo',$repeatInfo,null);
- }
- return $repeatInfo;
- }
-
- /**
- * @return string caption of the table layout
- */
- public function getCaption()
- {
- return $this->getRepeatInfo()->getCaption();
- }
-
- /**
- * @param string caption of the table layout
- */
- public function setCaption($value)
- {
- $this->getRepeatInfo()->setCaption($value);
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getRepeatInfo()->getCaptionAlign();
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout.
- */
- public function setCaptionAlign($value)
- {
- $this->getRepeatInfo()->setCaptionAlign($value);
- }
-
- /**
- * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->getRepeatInfo()->getRepeatColumns();
- }
-
- /**
- * @param integer the number of columns that the list should be displayed with.
- */
- public function setRepeatColumns($value)
- {
- $this->getRepeatInfo()->setRepeatColumns($value);
- }
-
- /**
- * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
- */
- public function getRepeatDirection()
- {
- return $this->getRepeatInfo()->getRepeatDirection();
- }
-
- /**
- * @param TRepeatDirection the direction of traversing the list
- */
- public function setRepeatDirection($value)
- {
- $this->getRepeatInfo()->setRepeatDirection($value);
- }
-
- /**
- * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
- */
- public function getRepeatLayout()
- {
- return $this->getRepeatInfo()->getRepeatLayout();
- }
-
- /**
- * @param TRepeatLayout how the list should be displayed, using table or using line breaks
- */
- public function setRepeatLayout($value)
- {
- $this->getRepeatInfo()->setRepeatLayout($value);
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * datalist items and their child controls.
- * If the event parameter is {@link TDataListCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataListCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- if(($item=$param->getItem()) instanceof IItemDataRenderer)
- $this->setSelectedItemIndex($item->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked after a data list item is created and instantiated with
- * template, but before added to the page hierarchy.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked right after an item is data bound.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event.
- * @param TDataListCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnEditCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnDeleteCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnUpdateCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnCancelCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Returns a value indicating whether this control contains header item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has header
- */
- public function getHasHeader()
- {
- return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains footer item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has footer
- */
- public function getHasFooter()
- {
- return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains separator items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasSeparators()
- {
- return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- }
-
- /**
- * Returns a style used for rendering items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer index of the item being rendered
- * @return TStyle item style
- */
- public function generateItemStyle($itemType,$index)
- {
- if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
- {
- $style=$item->getStyle();
- $item->clearStyle();
- return $style;
- }
- else
- return null;
- }
-
- /**
- * Renders an item in the list.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param THtmlWriter writer for rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the item in the item list
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index)
- {
- $item=$this->getItem($itemType,$index);
- if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
- $item->setTagName('div');
- $item->renderControl($writer);
- }
-
- /**
- * @param TListItemType item type
- * @param integer item index
- * @return TControl data list item with the specified item type and index
- */
- private function getItem($itemType,$index)
- {
- switch($itemType)
- {
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- case TListItemType::EditItem:
- return $this->getItems()->itemAt($index);
- case TListItemType::Header:
- return $this->getControls()->itemAt(0);
- case TListItemType::Footer:
- return $this->getControls()->itemAt($this->getControls()->getCount()-1);
- case TListItemType::Separator:
- $i=$index+$index+1;
- if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
- $i++;
- return $this->getControls()->itemAt($i);
- }
- return null;
- }
-
- /**
- * Creates a datalist item.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @return TControl the created item, null if item is not created
- */
- private function createItemInternal($itemIndex,$itemType)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a datalist item and performs databinding.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @param mixed data to be associated with the item
- * @return TControl the created item, null if item is not created
- */
- private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- if($item instanceof IDataRenderer)
- $item->setData($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- return $item;
- }
- else
- return null;
- }
-
- private function getAlternatingItemDisplay()
- {
- if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return array($classPath,$this->_alternatingItemTemplate);
- }
-
- private function getSelectedItemDisplay($itemIndex)
- {
- if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
- {
- if($itemIndex%2===0)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return $this->getAlternatingItemDisplay();
- }
- else
- return array($classPath,$this->_selectedItemTemplate);
- }
-
- private function getEditItemDisplay($itemIndex)
- {
- if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
- return $this->getSelectedItemDisplay($itemIndex);
- else
- return array($classPath,$this->_editItemTemplate);
- }
-
- /**
- * Creates a datalist item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TControl created datalist item
- */
- protected function createItem($itemIndex,$itemType)
- {
- $template=null;
- $classPath=null;
- switch($itemType)
- {
- case TListItemType::Item :
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- break;
- case TListItemType::AlternatingItem :
- list($classPath,$template)=$this->getAlternatingItemDisplay();
- break;
- case TListItemType::SelectedItem:
- list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
- break;
- case TListItemType::EditItem:
- list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
- break;
- case TListItemType::Header :
- $classPath=$this->getHeaderRenderer();
- $template=$this->_headerTemplate;
- break;
- case TListItemType::Footer :
- $classPath=$this->getFooterRenderer();
- $template=$this->_footerTemplate;
- break;
- case TListItemType::Separator :
- $classPath=$this->getSeparatorRenderer();
- $template=$this->_separatorTemplate;
- break;
- default:
- throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
- }
- if($classPath!=='')
- {
- $item=Prado::createComponent($classPath);
- if($item instanceof IItemDataRenderer)
- {
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- }
- }
- else if($template!==null)
- {
- $item=new TDataListItem;
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- $template->instantiateIn($item);
- }
- else
- $item=null;
-
- return $item;
- }
-
- /**
- * Creates empty datalist content.
- */
- protected function createEmptyContent()
- {
- if(($classPath=$this->getEmptyRenderer())!=='')
- $this->getControls()->add(Prado::createComponent($classPath));
- else if($this->_emptyTemplate!==null)
- $this->_emptyTemplate->instantiateIn($this);
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- // apply header style if any
- if($this->_header!==null && $this->_header instanceof IStyleable)
- {
- if($headerStyle=$this->getViewState('HeaderStyle',null))
- $this->_header->getStyle()->mergeWith($headerStyle);
- }
-
- // apply footer style if any
- if($this->_footer!==null && $this->_footer instanceof IStyleable)
- {
- if($footerStyle=$this->getViewState('FooterStyle',null))
- $this->_footer->getStyle()->mergeWith($footerStyle);
- }
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
-
- // apply item styles if any
- foreach($this->getItems() as $index=>$item)
- {
- if($index===$editIndex)
- $style=$editItemStyle;
- else if($index===$selectedIndex)
- $style=$selectedItemStyle;
- else if($index%2===0)
- $style=$itemStyle;
- else
- $style=$alternatingItemStyle;
- if($style && $item instanceof IStyleable)
- $item->getStyle()->mergeWith($style);
- }
-
- // apply separator style if any
- if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
- {
- $controls=$this->getControls();
- $count=$controls->getCount();
- for($i=$this->_header?2:1;$i<$count;$i+=2)
- {
- if(($separator=$controls->itemAt($i)) instanceof IStyleable)
- $separator->getStyle()->mergeWith($separatorStyle);
- }
- }
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getIsDataBound())
- $this->restoreItemsFromViewState();
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Clears up all items in the data list.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- }
-
- /**
- * Creates data list items based on viewstate information.
- */
- protected function restoreItemsFromViewState()
- {
- $this->reset();
- if(($itemCount=$this->getViewState('ItemCount',0))>0)
- {
- $items=$this->getItems();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $this->_header=$this->createItemInternal(-1,TListItemType::Header);
- for($i=0;$i<$itemCount;++$i)
- {
- if($hasSeparator && $i>0)
- $this->createItemInternal($i-1,TListItemType::Separator);
- if($i===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($i===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemInternal($i,$itemType));
- }
- $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
- }
- else
- $this->createEmptyContent();
- $this->clearChildState();
- }
-
- /**
- * Performs databinding to populate data list items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
- $itemIndex=0;
- $items=$this->getItems();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$dataItem)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($dataItem,$keyField));
- else
- $keys->add($key);
- if($itemIndex===0)
- $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
- if($hasSeparator && $itemIndex>0)
- $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
- if($itemIndex===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($itemIndex===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
- $itemIndex++;
- }
- if($itemIndex>0)
- $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
- else
- {
- $this->createEmptyContent();
- $this->dataBindChildren();
- }
- $this->setViewState('ItemCount',$itemIndex,0);
- }
-
- /**
- * Renders the data list control.
- * This method overrides the parent implementation.
- * @param THtmlWriter writer for rendering purpose.
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- if($this->getItemCount()>0)
- {
- $this->applyItemStyles();
- $repeatInfo=$this->getRepeatInfo();
- $repeatInfo->renderRepeater($writer,$this);
- }
- else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
- parent::render($writer);
- }
- }
-}
-
-
-/**
- * TDataListItemEventParameter class
- *
- * TDataListItemEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
- * The {@link getItem Item} property indicates the DataList item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemEventParameter extends TEventParameter
-{
- /**
- * The datalist item control responsible for the event.
- * @var TControl
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TControl DataList item related with the corresponding event
- */
- public function __construct($item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TControl datalist item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataListCommandEventParameter class
- *
- * TDataListCommandEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
- *
- * The {@link getItem Item} property indicates the DataList item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TControl the datalist item control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>OnCommand</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl datalist item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TControl the datalist item control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataListItem class
- *
- * A TDataListItem control represents an item in the {@link TDataList} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of DataList
- */
- private $_itemIndex;
- /**
- * type of the TDataListItem
- * @var TListItemType
- */
- private $_itemType;
- /**
- * value of the data associated with this item
- * @var mixed
- */
- private $_data;
-
- private $_tagName='span';
-
- /**
- * Returns the tag name used for this control.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return $this->_tagName;
- }
-
- /**
- * @param string tag name of the control to be rendered
- */
- public function setTagName($value)
- {
- $this->_tagName=$value;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by a datalist item.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datalist
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-/**
- * TDataListItemCollection class.
- *
- * TDataListItemCollection represents a collection of data list items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TControl descendants.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TBaseDataList class + */ +Prado::using('System.Web.UI.WebControls.TBaseDataList'); +/** + * Includes TRepeatInfo class + */ +Prado::using('System.Web.UI.WebControls.TRepeatInfo'); + +/** + * TDataList class + * + * TDataList represents a data bound and updatable list control. + * + * Like {@link TRepeater}, TDataList displays its content repeatedly based on + * the data fetched from {@link setDataSource DataSource}. + * The repeated contents in TDataList are called items, which are controls and + * can be accessed through {@link getItems Items}. When {@link dataBind()} is + * invoked, TDataList creates an item for each row of data and binds the data + * row to the item. Optionally, a TDataList can have a header, a footer and/or + * separators between items. + * + * TDataList differs from {@link TRepeater} in that it supports tiling the items + * in different manners and it maintains status of items to handle data update. + * + * The layout of the repeated contents are specified by inline templates. + * TDataList items, header, footer, etc. are being instantiated with the corresponding + * templates when data is being bound to the repeater. + * + * Since v3.1.0, the layout can also be by renderers. A renderer is a control class + * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed + * as an external template (in fact, it can also be non-templated controls). + * + * A renderer can be any control class. + * - If the class implements {@link IDataRenderer}, the <b>Data</b> + * property will be set as the data row during databinding. Many PRADO controls + * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. + * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set + * as the zero-based index of the item in the datalist item collection, and + * the <b>ItemType</b> property as the item's type (such as TListItemType::Item). + * {@link TDataListItemRenderer} may be used as the convenient base class which + * already implements {@link IDataItemRenderer}. + * + * The following properties are used to specify different types of template and renderer + * for a datalist: + * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}: + * for each repeated row of data + * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}: + * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer} + * will be used instead. + * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}: + * for the datalist header. + * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}: + * for the datalist footer. + * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}: + * for content to be displayed between items. + * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}: + * used when data bound to the datalist is empty. + * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}: + * for the row being editted. + * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}: + * for the row being selected. + * + * If a content type is defined with both a template and a renderer, the latter takes precedence. + * + * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data: + * - create item based on templates or renderers + * - set the row of data to the item + * - raise {@link onItemCreated OnItemCreated}: + * - add the item as a child control + * - call dataBind() of the item + * - raise {@link onItemDataBound OnItemDataBound}: + * + * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control + * within some datalist item raises a <b>OnCommand</b> event. Therefore, + * you can handle all sorts of <b>OnCommand</b> event in a central place by + * writing an event handler for {@link onItemCommand OnItemCommand}. + * + * An additional event is raised if the <b>OnCommand</b> event has one of the following + * command names: + * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised. + * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised. + * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised. + * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised. + * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised. + * + * TDataList provides a few properties to support tiling the items. + * The number of columns used to display the data items is specified via + * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} + * governs the order of the items being rendered. + * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout}, + * which can take one of the following values: + * - Table (default): items are organized using HTML table and cells. + * When using this layout, one can set {@link setCellPadding CellPadding} and + * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding + * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign} + * to add a table caption with the specified alignment. + * - Flow: items are organized using HTML spans and breaks. + * - Raw: TDataList does not generate any HTML tags to do the tiling. + * + * Items in TDataList can be in one of the three status: normal browsing, + * being editted and being selected. To change the status of a particular + * item, set {@link setSelectedItemIndex SelectedItemIndex} or + * {@link setEditItemIndex EditItemIndex}. The former will change + * the indicated item to selected mode, which will cause the item to + * use {@link setSelectedItemTemplate SelectedItemTemplate} or + * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation. + * The latter will change the indicated item to edit mode and to use corresponding + * template or renderer. + * Note, if an item is in edit mode, then selecting this item will have no effect. + * + * Different styles may be applied to items in different status. The style + * application is performed in a hierarchical way: Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * - item's own style + * - {@link getItemStyle ItemStyle} + * - {@link getAlternatingItemStyle AlternatingItemStyle} + * - {@link getSelectedItemStyle SelectedItemStyle} + * - {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + * + * When a page containing a datalist is post back, the datalist will restore automatically + * all its contents, including items, header, footer and separators. + * However, the data row associated with each item will not be recovered and become null. + * To access the data, use one of the following ways: + * - Use {@link getDataKeys DataKeys} to obtain the data key associated with + * the specified datalist item and use the key to fetch the corresponding data + * from some persistent storage such as DB. + * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback. + * Be aware though, if the size of your dataset is big, your page size will become big. Some + * complex data may also have serializing problem if saved in viewstate. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser +{ + /** + * Command name that TDataList understands. They are case-insensitive. + */ + const CMD_SELECT='Select'; + const CMD_EDIT='Edit'; + const CMD_UPDATE='Update'; + const CMD_DELETE='Delete'; + const CMD_CANCEL='Cancel'; + + /** + * @var TDataListItemCollection item list + */ + private $_items=null; + /** + * @var Itemplate various item templates + */ + private $_itemTemplate=null; + private $_emptyTemplate=null; + private $_alternatingItemTemplate=null; + private $_selectedItemTemplate=null; + private $_editItemTemplate=null; + private $_headerTemplate=null; + private $_footerTemplate=null; + private $_separatorTemplate=null; + /** + * @var TControl header item + */ + private $_header=null; + /** + * @var TControl footer item + */ + private $_footer=null; + + /** + * @return TDataListItemCollection item list + */ + public function getItems() + { + if(!$this->_items) + $this->_items=new TDataListItemCollection; + return $this->_items; + } + + /** + * @return integer number of items + */ + public function getItemCount() + { + return $this->_items?$this->_items->getCount():0; + } + + /** + * @return string the class name for datalist items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getItemRenderer() + { + return $this->getViewState('ItemRenderer',''); + } + + /** + * Sets the item renderer class. + * + * If not empty, the class will be used to instantiate as datalist items. + * This property takes precedence over {@link getItemTemplate ItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setItemTemplate + * @since 3.1.0 + */ + public function setItemRenderer($value) + { + $this->setViewState('ItemRenderer',$value,''); + } + + /** + * @return string the class name for alternative datalist items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getAlternatingItemRenderer() + { + return $this->getViewState('AlternatingItemRenderer',''); + } + + /** + * Sets the alternative item renderer class. + * + * If not empty, the class will be used to instantiate as alternative datalist items. + * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setAlternatingItemTemplate + * @since 3.1.0 + */ + public function setAlternatingItemRenderer($value) + { + $this->setViewState('AlternatingItemRenderer',$value,''); + } + + /** + * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEditItemRenderer() + { + return $this->getViewState('EditItemRenderer',''); + } + + /** + * Sets the renderer class for the datalist item being editted. + * + * If not empty, the class will be used to instantiate as the datalist item. + * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setEditItemTemplate + * @since 3.1.0 + */ + public function setEditItemRenderer($value) + { + $this->setViewState('EditItemRenderer',$value,''); + } + + /** + * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getSelectedItemRenderer() + { + return $this->getViewState('SelectedItemRenderer',''); + } + + /** + * Sets the renderer class for the datalist item being selected. + * + * If not empty, the class will be used to instantiate as the datalist item. + * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setSelectedItemTemplate + * @since 3.1.0 + */ + public function setSelectedItemRenderer($value) + { + $this->setViewState('SelectedItemRenderer',$value,''); + } + + /** + * @return string the class name for datalist item separators. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getSeparatorRenderer() + { + return $this->getViewState('SeparatorRenderer',''); + } + + /** + * Sets the datalist item separator renderer class. + * + * If not empty, the class will be used to instantiate as datalist item separators. + * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setSeparatorTemplate + * @since 3.1.0 + */ + public function setSeparatorRenderer($value) + { + $this->setViewState('SeparatorRenderer',$value,''); + } + + /** + * @return string the class name for datalist header item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getHeaderRenderer() + { + return $this->getViewState('HeaderRenderer',''); + } + + /** + * Sets the datalist header renderer class. + * + * If not empty, the class will be used to instantiate as datalist header item. + * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setHeaderTemplate + * @since 3.1.0 + */ + public function setHeaderRenderer($value) + { + $this->setViewState('HeaderRenderer',$value,''); + } + + /** + * @return string the class name for datalist footer item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getFooterRenderer() + { + return $this->getViewState('FooterRenderer',''); + } + + /** + * Sets the datalist footer renderer class. + * + * If not empty, the class will be used to instantiate as datalist footer item. + * This property takes precedence over {@link getFooterTemplate FooterTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setFooterTemplate + * @since 3.1.0 + */ + public function setFooterRenderer($value) + { + $this->setViewState('FooterRenderer',$value,''); + } + + /** + * @return string the class name for empty datalist item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEmptyRenderer() + { + return $this->getViewState('EmptyRenderer',''); + } + + /** + * Sets the datalist empty renderer class. + * + * The empty renderer is created as the child of the datalist + * if data bound to the datalist is empty. + * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setEmptyTemplate + * @since 3.1.0 + */ + public function setEmptyRenderer($value) + { + $this->setViewState('EmptyRenderer',$value,''); + } + + /** + * @return ITemplate the template for item + */ + public function getItemTemplate() + { + return $this->_itemTemplate; + } + + /** + * @param ITemplate the template for item + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_itemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate'); + } + + /** + * @return TTableItemStyle the style for item + */ + public function getItemStyle() + { + if(($style=$this->getViewState('ItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('ItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the template for each alternating item + */ + public function getAlternatingItemTemplate() + { + return $this->_alternatingItemTemplate; + } + + /** + * @param ITemplate the template for each alternating item + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setAlternatingItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_alternatingItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType'); + } + + /** + * @return TTableItemStyle the style for each alternating item + */ + public function getAlternatingItemStyle() + { + if(($style=$this->getViewState('AlternatingItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('AlternatingItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the selected item template + */ + public function getSelectedItemTemplate() + { + return $this->_selectedItemTemplate; + } + + /** + * @param ITemplate the selected item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setSelectedItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_selectedItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate'); + } + + /** + * @return TTableItemStyle the style for selected item + */ + public function getSelectedItemStyle() + { + if(($style=$this->getViewState('SelectedItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SelectedItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the edit item template + */ + public function getEditItemTemplate() + { + return $this->_editItemTemplate; + } + + /** + * @param ITemplate the edit item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEditItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_editItemTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate'); + } + + /** + * @return TTableItemStyle the style for edit item + */ + public function getEditItemStyle() + { + if(($style=$this->getViewState('EditItemStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('EditItemStyle',$style,null); + } + return $style; + } + + /** + * @return ITemplate the header template + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate the header template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setHeaderTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_headerTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate'); + } + + /** + * @return TTableItemStyle the style for header + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return TControl the header item + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return ITemplate the footer template + */ + public function getFooterTemplate() + { + return $this->_footerTemplate; + } + + /** + * @param ITemplate the footer template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setFooterTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_footerTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate'); + } + + /** + * @return TTableItemStyle the style for footer + */ + public function getFooterStyle() + { + if(($style=$this->getViewState('FooterStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('FooterStyle',$style,null); + } + return $style; + } + + /** + * @return TControl the footer item + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * @return ITemplate the template applied when no data is bound to the datalist + */ + public function getEmptyTemplate() + { + return $this->_emptyTemplate; + } + + /** + * @param ITemplate the template applied when no data is bound to the datalist + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEmptyTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_emptyTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate'); + } + + /** + * @return ITemplate the separator template + */ + public function getSeparatorTemplate() + { + return $this->_separatorTemplate; + } + + /** + * @param ITemplate the separator template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setSeparatorTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_separatorTemplate=$value; + else + throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate'); + } + + /** + * @return TTableItemStyle the style for separator + */ + public function getSeparatorStyle() + { + if(($style=$this->getViewState('SeparatorStyle',null))===null) + { + $style=new TTableItemStyle; + $this->setViewState('SeparatorStyle',$style,null); + } + return $style; + } + + /** + * @return integer the zero-based index of the selected item in {@link getItems Items}. + * A value -1 means no item selected. + */ + public function getSelectedItemIndex() + { + return $this->getViewState('SelectedItemIndex',-1); + } + + /** + * Selects an item by its index in {@link getItems Items}. + * Previously selected item will be un-selected. + * If the item to be selected is already in edit mode, it will remain in edit mode. + * If the index is less than 0, any existing selection will be cleared up. + * @param integer the selected item index + */ + public function setSelectedItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getSelectedItemIndex())!==$value) + { + $this->setViewState('SelectedItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + { + $item=$items->itemAt($current); + if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) + $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); + } + if($value>=0 && $value<$itemCount) + { + $item=$items->itemAt($value); + if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem) + $item->setItemType(TListItemType::SelectedItem); + } + } + } + + /** + * @return TControl the selected item, null if no item is selected. + */ + public function getSelectedItem() + { + $index=$this->getSelectedItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return mixed the key value of the currently selected item + * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty. + */ + public function getSelectedDataKey() + { + if($this->getDataKeyField()==='') + throw new TInvalidOperationException('datalist_datakeyfield_required'); + $index=$this->getSelectedItemIndex(); + $dataKeys=$this->getDataKeys(); + if($index>=0 && $index<$dataKeys->getCount()) + return $dataKeys->itemAt($index); + else + return null; + } + + /** + * @return integer the zero-based index of the edit item in {@link getItems Items}. + * A value -1 means no item is in edit mode. + */ + public function getEditItemIndex() + { + return $this->getViewState('EditItemIndex',-1); + } + + /** + * Edits an item by its index in {@link getItems Items}. + * Previously editting item will change to normal item state. + * If the index is less than 0, any existing edit item will be cleared up. + * @param integer the edit item index + */ + public function setEditItemIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + if(($current=$this->getEditItemIndex())!==$value) + { + $this->setViewState('EditItemIndex',$value,-1); + $items=$this->getItems(); + $itemCount=$items->getCount(); + if($current>=0 && $current<$itemCount) + $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item); + if($value>=0 && $value<$itemCount) + $items->itemAt($value)->setItemType(TListItemType::EditItem); + } + } + + /** + * @return TControl the edit item + */ + public function getEditItem() + { + $index=$this->getEditItemIndex(); + $items=$this->getItems(); + if($index>=0 && $index<$items->getCount()) + return $items->itemAt($index); + else + return null; + } + + /** + * @return boolean whether the header should be shown. Defaults to true. + */ + public function getShowHeader() + { + return $this->getViewState('ShowHeader',true); + } + + /** + * @param boolean whether to show header + */ + public function setShowHeader($value) + { + $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the footer should be shown. Defaults to true. + */ + public function getShowFooter() + { + return $this->getViewState('ShowFooter',true); + } + + /** + * @param boolean whether to show footer + */ + public function setShowFooter($value) + { + $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return TRepeatInfo repeat information (primarily used by control developers) + */ + protected function getRepeatInfo() + { + if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null) + { + $repeatInfo=new TRepeatInfo; + $this->setViewState('RepeatInfo',$repeatInfo,null); + } + return $repeatInfo; + } + + /** + * @return string caption of the table layout + */ + public function getCaption() + { + return $this->getRepeatInfo()->getCaption(); + } + + /** + * @param string caption of the table layout + */ + public function setCaption($value) + { + $this->getRepeatInfo()->setCaption($value); + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->getRepeatInfo()->getCaptionAlign(); + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. + */ + public function setCaptionAlign($value) + { + $this->getRepeatInfo()->setCaptionAlign($value); + } + + /** + * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set. + */ + public function getRepeatColumns() + { + return $this->getRepeatInfo()->getRepeatColumns(); + } + + /** + * @param integer the number of columns that the list should be displayed with. + */ + public function setRepeatColumns($value) + { + $this->getRepeatInfo()->setRepeatColumns($value); + } + + /** + * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical + */ + public function getRepeatDirection() + { + return $this->getRepeatInfo()->getRepeatDirection(); + } + + /** + * @param TRepeatDirection the direction of traversing the list + */ + public function setRepeatDirection($value) + { + $this->getRepeatInfo()->setRepeatDirection($value); + } + + /** + * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table. + */ + public function getRepeatLayout() + { + return $this->getRepeatInfo()->getRepeatLayout(); + } + + /** + * @param TRepeatLayout how the list should be displayed, using table or using line breaks + */ + public function setRepeatLayout($value) + { + $this->getRepeatInfo()->setRepeatLayout($value); + } + + /** + * This method overrides parent's implementation to handle + * {@link onItemCommand OnItemCommand} event which is bubbled from + * datalist items and their child controls. + * If the event parameter is {@link TDataListCommandEventParameter} and + * the command name is a recognized one, which includes 'select', 'edit', + * 'delete', 'update', and 'cancel' (case-insensitive), then a + * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}). + * This method should only be used by control developers. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TDataListCommandEventParameter) + { + $this->onItemCommand($param); + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_SELECT)===0) + { + if(($item=$param->getItem()) instanceof IItemDataRenderer) + $this->setSelectedItemIndex($item->getItemIndex()); + $this->onSelectedIndexChanged($param); + return true; + } + else if(strcasecmp($command,self::CMD_EDIT)===0) + { + $this->onEditCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_DELETE)===0) + { + $this->onDeleteCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_UPDATE)===0) + { + $this->onUpdateCommand($param); + return true; + } + else if(strcasecmp($command,self::CMD_CANCEL)===0) + { + $this->onCancelCommand($param); + return true; + } + } + return false; + } + + + /** + * Raises <b>OnItemCreated</b> event. + * This method is invoked after a data list item is created and instantiated with + * template, but before added to the page hierarchy. + * The datalist item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TDataListItemEventParameter event parameter + */ + public function onItemCreated($param) + { + $this->raiseEvent('OnItemCreated',$this,$param); + } + + /** + * Raises <b>OnItemDataBound</b> event. + * This method is invoked right after an item is data bound. + * The datalist item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TDataListItemEventParameter event parameter + */ + public function onItemDataBound($param) + { + $this->raiseEvent('OnItemDataBound',$this,$param); + } + + /** + * Raises <b>OnItemCommand</b> event. + * This method is invoked when a child control of the data list + * raises an <b>OnCommand</b> event. + * @param TDataListCommandEventParameter event parameter + */ + public function onItemCommand($param) + { + $this->raiseEvent('OnItemCommand',$this,$param); + } + + /** + * Raises <b>OnEditCommand</b> event. + * This method is invoked when a child control of the data list + * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onEditCommand($param) + { + $this->raiseEvent('OnEditCommand',$this,$param); + } + + /** + * Raises <b>OnDeleteCommand</b> event. + * This method is invoked when a child control of the data list + * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onDeleteCommand($param) + { + $this->raiseEvent('OnDeleteCommand',$this,$param); + } + + /** + * Raises <b>OnUpdateCommand</b> event. + * This method is invoked when a child control of the data list + * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onUpdateCommand($param) + { + $this->raiseEvent('OnUpdateCommand',$this,$param); + } + + /** + * Raises <b>OnCancelCommand</b> event. + * This method is invoked when a child control of the data list + * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive). + * @param TDataListCommandEventParameter event parameter + */ + public function onCancelCommand($param) + { + $this->raiseEvent('OnCancelCommand',$this,$param); + } + + /** + * Returns a value indicating whether this control contains header item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean whether the datalist has header + */ + public function getHasHeader() + { + return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')); + } + + /** + * Returns a value indicating whether this control contains footer item. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean whether the datalist has footer + */ + public function getHasFooter() + { + return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!=='')); + } + + /** + * Returns a value indicating whether this control contains separator items. + * This method is required by {@link IRepeatInfoUser} interface. + * @return boolean always false. + */ + public function getHasSeparators() + { + return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + } + + /** + * Returns a style used for rendering items. + * This method is required by {@link IRepeatInfoUser} interface. + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer index of the item being rendered + * @return TStyle item style + */ + public function generateItemStyle($itemType,$index) + { + if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle()) + { + $style=$item->getStyle(); + $item->clearStyle(); + return $style; + } + else + return null; + } + + /** + * Renders an item in the list. + * This method is required by {@link IRepeatInfoUser} interface. + * @param THtmlWriter writer for rendering purpose + * @param TRepeatInfo repeat information + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer zero-based index of the item in the item list + */ + public function renderItem($writer,$repeatInfo,$itemType,$index) + { + $item=$this->getItem($itemType,$index); + if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem') + $item->setTagName('div'); + $item->renderControl($writer); + } + + /** + * @param TListItemType item type + * @param integer item index + * @return TControl data list item with the specified item type and index + */ + private function getItem($itemType,$index) + { + switch($itemType) + { + case TListItemType::Item: + case TListItemType::AlternatingItem: + case TListItemType::SelectedItem: + case TListItemType::EditItem: + return $this->getItems()->itemAt($index); + case TListItemType::Header: + return $this->getControls()->itemAt(0); + case TListItemType::Footer: + return $this->getControls()->itemAt($this->getControls()->getCount()-1); + case TListItemType::Separator: + $i=$index+$index+1; + if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='') + $i++; + return $this->getControls()->itemAt($i); + } + return null; + } + + /** + * Creates a datalist item. + * This method invokes {@link createItem} to create a new datalist item. + * @param integer zero-based item index. + * @param TListItemType item type + * @return TControl the created item, null if item is not created + */ + private function createItemInternal($itemIndex,$itemType) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TDataListItemEventParameter($item); + $this->onItemCreated($param); + $this->getControls()->add($item); + return $item; + } + else + return null; + } + + /** + * Creates a datalist item and performs databinding. + * This method invokes {@link createItem} to create a new datalist item. + * @param integer zero-based item index. + * @param TListItemType item type + * @param mixed data to be associated with the item + * @return TControl the created item, null if item is not created + */ + private function createItemWithDataInternal($itemIndex,$itemType,$dataItem) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TDataListItemEventParameter($item); + if($item instanceof IDataRenderer) + $item->setData($dataItem); + $this->onItemCreated($param); + $this->getControls()->add($item); + $item->dataBind(); + $this->onItemDataBound($param); + return $item; + } + else + return null; + } + + private function getAlternatingItemDisplay() + { + if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null) + return array($this->getItemRenderer(),$this->_itemTemplate); + else + return array($classPath,$this->_alternatingItemTemplate); + } + + private function getSelectedItemDisplay($itemIndex) + { + if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null) + { + if($itemIndex%2===0) + return array($this->getItemRenderer(),$this->_itemTemplate); + else + return $this->getAlternatingItemDisplay(); + } + else + return array($classPath,$this->_selectedItemTemplate); + } + + private function getEditItemDisplay($itemIndex) + { + if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null) + return $this->getSelectedItemDisplay($itemIndex); + else + return array($classPath,$this->_editItemTemplate); + } + + /** + * Creates a datalist item instance based on the item type and index. + * @param integer zero-based item index + * @param TListItemType item type + * @return TControl created datalist item + */ + protected function createItem($itemIndex,$itemType) + { + $template=null; + $classPath=null; + switch($itemType) + { + case TListItemType::Item : + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + break; + case TListItemType::AlternatingItem : + list($classPath,$template)=$this->getAlternatingItemDisplay(); + break; + case TListItemType::SelectedItem: + list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex); + break; + case TListItemType::EditItem: + list($classPath,$template)=$this->getEditItemDisplay($itemIndex); + break; + case TListItemType::Header : + $classPath=$this->getHeaderRenderer(); + $template=$this->_headerTemplate; + break; + case TListItemType::Footer : + $classPath=$this->getFooterRenderer(); + $template=$this->_footerTemplate; + break; + case TListItemType::Separator : + $classPath=$this->getSeparatorRenderer(); + $template=$this->_separatorTemplate; + break; + default: + throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType); + } + if($classPath!=='') + { + $item=Prado::createComponent($classPath); + if($item instanceof IItemDataRenderer) + { + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + } + } + else if($template!==null) + { + $item=new TDataListItem; + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + $template->instantiateIn($item); + } + else + $item=null; + + return $item; + } + + /** + * Creates empty datalist content. + */ + protected function createEmptyContent() + { + if(($classPath=$this->getEmptyRenderer())!=='') + $this->getControls()->add(Prado::createComponent($classPath)); + else if($this->_emptyTemplate!==null) + $this->_emptyTemplate->instantiateIn($this); + } + + /** + * Applies styles to items, header, footer and separators. + * Item styles are applied in a hierarchical way. Style in higher hierarchy + * will inherit from styles in lower hierarchy. + * Starting from the lowest hierarchy, the item styles include + * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle}, + * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}. + * Therefore, if background color is set as red in {@link getItemStyle ItemStyle}, + * {@link getEditItemStyle EditItemStyle} will also have red background color + * unless it is set to a different value explicitly. + */ + protected function applyItemStyles() + { + $itemStyle=$this->getViewState('ItemStyle',null); + + $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null); + if($itemStyle!==null) + { + if($alternatingItemStyle===null) + $alternatingItemStyle=$itemStyle; + else + $alternatingItemStyle->mergeWith($itemStyle); + } + + $selectedItemStyle=$this->getViewState('SelectedItemStyle',null); + + $editItemStyle=$this->getViewState('EditItemStyle',null); + if($selectedItemStyle!==null) + { + if($editItemStyle===null) + $editItemStyle=$selectedItemStyle; + else + $editItemStyle->mergeWith($selectedItemStyle); + } + + // apply header style if any + if($this->_header!==null && $this->_header instanceof IStyleable) + { + if($headerStyle=$this->getViewState('HeaderStyle',null)) + $this->_header->getStyle()->mergeWith($headerStyle); + } + + // apply footer style if any + if($this->_footer!==null && $this->_footer instanceof IStyleable) + { + if($footerStyle=$this->getViewState('FooterStyle',null)) + $this->_footer->getStyle()->mergeWith($footerStyle); + } + + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + + // apply item styles if any + foreach($this->getItems() as $index=>$item) + { + if($index===$editIndex) + $style=$editItemStyle; + else if($index===$selectedIndex) + $style=$selectedItemStyle; + else if($index%2===0) + $style=$itemStyle; + else + $style=$alternatingItemStyle; + if($style && $item instanceof IStyleable) + $item->getStyle()->mergeWith($style); + } + + // apply separator style if any + if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators()) + { + $controls=$this->getControls(); + $count=$controls->getCount(); + for($i=$this->_header?2:1;$i<$count;$i+=2) + { + if(($separator=$controls->itemAt($i)) instanceof IStyleable) + $separator->getStyle()->mergeWith($separatorStyle); + } + } + } + + /** + * Saves item count in viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if($this->_items) + $this->setViewState('ItemCount',$this->_items->getCount(),0); + else + $this->clearViewState('ItemCount'); + } + + /** + * Loads item count information from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + if(!$this->getIsDataBound()) + $this->restoreItemsFromViewState(); + $this->clearViewState('ItemCount'); + } + + /** + * Clears up all items in the data list. + */ + public function reset() + { + $this->getControls()->clear(); + $this->getItems()->clear(); + $this->_header=null; + $this->_footer=null; + } + + /** + * Creates data list items based on viewstate information. + */ + protected function restoreItemsFromViewState() + { + $this->reset(); + if(($itemCount=$this->getViewState('ItemCount',0))>0) + { + $items=$this->getItems(); + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + $this->_header=$this->createItemInternal(-1,TListItemType::Header); + for($i=0;$i<$itemCount;++$i) + { + if($hasSeparator && $i>0) + $this->createItemInternal($i-1,TListItemType::Separator); + if($i===$editIndex) + $itemType=TListItemType::EditItem; + else if($i===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else + $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item; + $items->add($this->createItemInternal($i,$itemType)); + } + $this->_footer=$this->createItemInternal(-1,TListItemType::Footer); + } + else + $this->createEmptyContent(); + $this->clearChildState(); + } + + /** + * Performs databinding to populate data list items from data source. + * This method is invoked by dataBind(). + * You may override this function to provide your own way of data population. + * @param Traversable the data + */ + protected function performDataBinding($data) + { + $this->reset(); + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + $itemIndex=0; + $items=$this->getItems(); + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + $selectedIndex=$this->getSelectedItemIndex(); + $editIndex=$this->getEditItemIndex(); + foreach($data as $key=>$dataItem) + { + if($keyField!=='') + $keys->add($this->getDataFieldValue($dataItem,$keyField)); + else + $keys->add($key); + if($itemIndex===0) + $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null); + if($hasSeparator && $itemIndex>0) + $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null); + if($itemIndex===$editIndex) + $itemType=TListItemType::EditItem; + else if($itemIndex===$selectedIndex) + $itemType=TListItemType::SelectedItem; + else + $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item; + $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem)); + $itemIndex++; + } + if($itemIndex>0) + $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null); + else + { + $this->createEmptyContent(); + $this->dataBindChildren(); + } + $this->setViewState('ItemCount',$itemIndex,0); + } + + /** + * Renders the data list control. + * This method overrides the parent implementation. + * @param THtmlWriter writer for rendering purpose. + */ + public function render($writer) + { + if($this->getHasControls()) + { + if($this->getItemCount()>0) + { + $this->applyItemStyles(); + $repeatInfo=$this->getRepeatInfo(); + $repeatInfo->renderRepeater($writer,$this); + } + else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='') + parent::render($writer); + } + } +} + + +/** + * TDataListItemEventParameter class + * + * TDataListItemEventParameter encapsulates the parameter data for + * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls. + * The {@link getItem Item} property indicates the DataList item related with the event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItemEventParameter extends TEventParameter +{ + /** + * The datalist item control responsible for the event. + * @var TControl + */ + private $_item=null; + + /** + * Constructor. + * @param TControl DataList item related with the corresponding event + */ + public function __construct($item) + { + $this->_item=$item; + } + + /** + * @return TControl datalist item related with the corresponding event + */ + public function getItem() + { + return $this->_item; + } +} + +/** + * TDataListCommandEventParameter class + * + * TDataListCommandEventParameter encapsulates the parameter data for + * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls. + * + * The {@link getItem Item} property indicates the DataList item related with the event. + * The {@link getCommandSource CommandSource} refers to the control that originally + * raises the Command event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListCommandEventParameter extends TCommandEventParameter +{ + /** + * @var TControl the datalist item control responsible for the event. + */ + private $_item=null; + /** + * @var TControl the control originally raises the <b>OnCommand</b> event. + */ + private $_source=null; + + /** + * Constructor. + * @param TControl datalist item responsible for the event + * @param TControl original event sender + * @param TCommandEventParameter original event parameter + */ + public function __construct($item,$source,TCommandEventParameter $param) + { + $this->_item=$item; + $this->_source=$source; + parent::__construct($param->getCommandName(),$param->getCommandParameter()); + } + + /** + * @return TControl the datalist item control responsible for the event. + */ + public function getItem() + { + return $this->_item; + } + + /** + * @return TControl the control originally raises the <b>OnCommand</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } +} + +/** + * TDataListItem class + * + * A TDataListItem control represents an item in the {@link TDataList} control, + * such as heading section, footer section, or a data item. + * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> + * and {@link getDataItem DataItem} properties, respectively. The type of the item + * is given by {@link getItemType ItemType} property. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer +{ + /** + * index of the data item in the Items collection of DataList + */ + private $_itemIndex; + /** + * type of the TDataListItem + * @var TListItemType + */ + private $_itemType; + /** + * value of the data associated with this item + * @var mixed + */ + private $_data; + + private $_tagName='span'; + + /** + * Returns the tag name used for this control. + * @return string tag name of the control to be rendered + */ + protected function getTagName() + { + return $this->_tagName; + } + + /** + * @param string tag name of the control to be rendered + */ + public function setTagName($value) + { + $this->_tagName=$value; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableItemStyle} to be used by a datalist item. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return TListItemType item type + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type. + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * @return integer zero-based index of the item in the item collection of datalist + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value) + { + $this->_itemIndex=TPropertyValue::ensureInteger($value); + } + + /** + * @return mixed data associated with the item + * @since 3.1.0 + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + * @since 3.1.0 + */ + public function setData($value) + { + $this->_data=$value; + } + + /** + * This property is deprecated since v3.1.0. + * @return mixed data associated with the item + * @deprecated deprecated since v3.1.0. Use {@link getData} instead. + */ + public function getDataItem() + { + return $this->getData(); + } + + /** + * This property is deprecated since v3.1.0. + * @param mixed data to be associated with the item + * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. + */ + public function setDataItem($value) + { + return $this->setData($value); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + +/** + * TDataListItemCollection class. + * + * TDataListItemCollection represents a collection of data list items. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataListItemCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only TControl descendants. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant. + */ + public function insertAt($index,$item) + { + if($item instanceof TControl) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required'); + } +} + diff --git a/framework/Web/UI/WebControls/TDataListItemRenderer.php b/framework/Web/UI/WebControls/TDataListItemRenderer.php index 7065dc09..53c48b6e 100644 --- a/framework/Web/UI/WebControls/TDataListItemRenderer.php +++ b/framework/Web/UI/WebControls/TDataListItemRenderer.php @@ -1,172 +1,172 @@ -<?php
-/**
- * TDataListItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataListItemRenderer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataList');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataListItemRenderer class
- *
- * TDataListItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataList}.
- *
- * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
- * the bubbling scheme for the OnCommand event of data list items.
- *
- * TDataListItemRenderer also implements the {@link IStyleable} interface,
- * which allows TDataList to apply CSS styles to the renders.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
-{
- /**
- * Creates a style object to be used by the control.
- * This method may be overriden by controls to provide customized style.
- * @return TStyle
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return boolean whether the control has defined any style information
- */
- public function getHasStyle()
- {
- return $this->getViewState('Style',null)!==null;
- }
-
- /**
- * @return TStyle the object representing the css style of the control
- */
- public function getStyle()
- {
- if($style=$this->getViewState('Style',null))
- return $style;
- else
- {
- $style=$this->createStyle();
- $this->setViewState('Style',$style,null);
- return $style;
- }
- }
-
- /**
- * Removes all style data.
- */
- public function clearStyle()
- {
- $this->clearViewState('Style');
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * Returns the tag name used for this control.
- * By default, the tag name is 'span'.
- * You can override this method to provide customized tag names.
- * If the tag name is empty, the opening and closing tag will NOT be rendered.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * By default, this method renders the style string.
- * The method can be overriden to provide customized attribute rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- if($style=$this->getViewState('Style',null))
- $style->addAttributesToRender($writer);
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by replacing it with
- * the following sequence:
- * - {@link renderBeginTag}
- * - {@link renderContents}
- * - {@link renderEndTag}
- * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getTagName()!=='')
- {
- $this->renderBeginTag($writer);
- $this->renderContents($writer);
- $this->renderEndTag($writer);
- }
- else
- $this->renderContents($writer);
- }
-
- /**
- * Renders the openning tag for the control (including attributes)
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag($this->getTagName());
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * By default, child controls and text strings will be rendered.
- * You can override this method to provide customized content rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- parent::renderChildren($writer);
- }
-
- /**
- * Renders the closing tag for the control
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- $writer->renderEndTag();
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataList'); +Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); + +/** + * TDataListItemRenderer class + * + * TDataListItemRenderer can be used as a convenient base class to + * define an item renderer class specific for {@link TDataList}. + * + * TDataListItemRenderer extends {@link TItemDataRenderer} and implements + * the bubbling scheme for the OnCommand event of data list items. + * + * TDataListItemRenderer also implements the {@link IStyleable} interface, + * which allows TDataList to apply CSS styles to the renders. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +class TDataListItemRenderer extends TItemDataRenderer implements IStyleable +{ + /** + * Creates a style object to be used by the control. + * This method may be overriden by controls to provide customized style. + * @return TStyle + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return boolean whether the control has defined any style information + */ + public function getHasStyle() + { + return $this->getViewState('Style',null)!==null; + } + + /** + * @return TStyle the object representing the css style of the control + */ + public function getStyle() + { + if($style=$this->getViewState('Style',null)) + return $style; + else + { + $style=$this->createStyle(); + $this->setViewState('Style',$style,null); + return $style; + } + } + + /** + * Removes all style data. + */ + public function clearStyle() + { + $this->clearViewState('Style'); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } + + /** + * Returns the tag name used for this control. + * By default, the tag name is 'span'. + * You can override this method to provide customized tag names. + * If the tag name is empty, the opening and closing tag will NOT be rendered. + * @return string tag name of the control to be rendered + */ + protected function getTagName() + { + return 'span'; + } + + /** + * Adds attribute name-value pairs to renderer. + * By default, this method renders the style string. + * The method can be overriden to provide customized attribute rendering. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + if($style=$this->getViewState('Style',null)) + $style->addAttributesToRender($writer); + } + + /** + * Renders the control. + * This method overrides the parent implementation by replacing it with + * the following sequence: + * - {@link renderBeginTag} + * - {@link renderContents} + * - {@link renderEndTag} + * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if($this->getTagName()!=='') + { + $this->renderBeginTag($writer); + $this->renderContents($writer); + $this->renderEndTag($writer); + } + else + $this->renderContents($writer); + } + + /** + * Renders the openning tag for the control (including attributes) + * This method is invoked when {@link getTagName TagName} is not empty. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + $this->addAttributesToRender($writer); + $writer->renderBeginTag($this->getTagName()); + } + + /** + * Renders the body content enclosed between the control tag. + * By default, child controls and text strings will be rendered. + * You can override this method to provide customized content rendering. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + parent::renderChildren($writer); + } + + /** + * Renders the closing tag for the control + * This method is invoked when {@link getTagName TagName} is not empty. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderEndTag($writer) + { + $writer->renderEndTag(); + } +} + diff --git a/framework/Web/UI/WebControls/TDataRenderer.php b/framework/Web/UI/WebControls/TDataRenderer.php index ece9d974..44ab0b1d 100644 --- a/framework/Web/UI/WebControls/TDataRenderer.php +++ b/framework/Web/UI/WebControls/TDataRenderer.php @@ -1,52 +1,52 @@ -<?php
-/**
- * TDataRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataRenderer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-
-/**
- * TDataRenderer class
- *
- * TDataRenderer is the convenient base class for template-based renderer controls.
- * It extends {@link TTemplateControl} and implements the methods required
- * by the {@link IDataRenderer} interface.
- *
- * The following property is provided by TDataRenderer:
- * - {@link getData Data}: data associated with this renderer.
-
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
-{
- /**
- * @var mixed data associated with this renderer
- */
- private $_data;
-
- /**
- * @return mixed data associated with the item
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ + +/** + * TDataRenderer class + * + * TDataRenderer is the convenient base class for template-based renderer controls. + * It extends {@link TTemplateControl} and implements the methods required + * by the {@link IDataRenderer} interface. + * + * The following property is provided by TDataRenderer: + * - {@link getData Data}: data associated with this renderer. + + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ +abstract class TDataRenderer extends TTemplateControl implements IDataRenderer +{ + /** + * @var mixed data associated with this renderer + */ + private $_data; + + /** + * @return mixed data associated with the item + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + */ + public function setData($value) + { + $this->_data=$value; + } +} + diff --git a/framework/Web/UI/WebControls/TDataSourceControl.php b/framework/Web/UI/WebControls/TDataSourceControl.php index 0b07810a..f7a224af 100644 --- a/framework/Web/UI/WebControls/TDataSourceControl.php +++ b/framework/Web/UI/WebControls/TDataSourceControl.php @@ -1,118 +1,118 @@ -<?php
-/**
- * IDataSource, TDataSourceControl, TReadOnlyDataSource class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * IDataSource, TDataSourceControl, TReadOnlyDataSource class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * IDataSource class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-interface IDataSource
-{
- public function getView($viewName);
- public function getViewNames();
- public function onDataSourceChanged($param);
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceControl extends TControl implements IDataSource
-{
- public function getView($viewName)
- {
- return null;
- }
-
- public function getViewNames()
- {
- return array();
- }
-
- public function onDataSourceChanged($param)
- {
- $this->raiseEvent('OnDataSourceChanged',$this,$param);
- }
-
- public function focus()
- {
- throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
- }
-
- public function getEnableTheming()
- {
- return false;
- }
-
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
- }
-
- public function getSkinID()
- {
- return '';
- }
-
- public function setSkinID($value)
- {
- throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
- }
-
- public function getVisible($checkParents=true)
- {
- return false;
- }
-
- public function setVisible($value)
- {
- throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
- }
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSource extends TDataSourceControl
-{
- private $_dataSource;
- private $_dataMember;
-
- public function __construct($dataSource,$dataMember)
- {
- if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
- throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
- $this->_dataSource=$dataSource;
- $this->_dataMember=$dataMember;
- }
-
- public function getView($viewName)
- {
- if($this->_dataSource instanceof IDataSource)
- return $this->_dataSource->getView($viewName);
- else
- return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * IDataSource class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +interface IDataSource +{ + public function getView($viewName); + public function getViewNames(); + public function onDataSourceChanged($param); +} + +/** + * TDataSourceControl class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataSourceControl extends TControl implements IDataSource +{ + public function getView($viewName) + { + return null; + } + + public function getViewNames() + { + return array(); + } + + public function onDataSourceChanged($param) + { + $this->raiseEvent('OnDataSourceChanged',$this,$param); + } + + public function focus() + { + throw new TNotSupportedException('datasourcecontrol_focus_unsupported'); + } + + public function getEnableTheming() + { + return false; + } + + public function setEnableTheming($value) + { + throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported'); + } + + public function getSkinID() + { + return ''; + } + + public function setSkinID($value) + { + throw new TNotSupportedException('datasourcecontrol_skinid_unsupported'); + } + + public function getVisible($checkParents=true) + { + return false; + } + + public function setVisible($value) + { + throw new TNotSupportedException('datasourcecontrol_visible_unsupported'); + } +} + +/** + * TDataSourceControl class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TReadOnlyDataSource extends TDataSourceControl +{ + private $_dataSource; + private $_dataMember; + + public function __construct($dataSource,$dataMember) + { + if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable)) + throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid'); + $this->_dataSource=$dataSource; + $this->_dataMember=$dataMember; + } + + public function getView($viewName) + { + if($this->_dataSource instanceof IDataSource) + return $this->_dataSource->getView($viewName); + else + return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource); + } +} + diff --git a/framework/Web/UI/WebControls/TDataSourceView.php b/framework/Web/UI/WebControls/TDataSourceView.php index 9e7c0128..af817a32 100644 --- a/framework/Web/UI/WebControls/TDataSourceView.php +++ b/framework/Web/UI/WebControls/TDataSourceView.php @@ -1,206 +1,206 @@ -<?php
-/**
- * TDataSourceSelectParameters, TDataSourceView, TReadOnlyDataSourceView class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataSourceSelectParameters, TDataSourceView, TReadOnlyDataSourceView class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataSourceSelectParameters class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataSourceSelectParameters extends TComponent
-{
- private $_retrieveTotalRowCount=false;
- private $_startRowIndex=0;
- private $_totalRowCount=0;
- private $_maximumRows=0;
-
- public function getStartRowIndex()
- {
- return $this->_startRowIndex;
- }
-
- public function setStartRowIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_startRowIndex=$value;
- }
-
- public function getMaximumRows()
- {
- return $this->_maximumRows;
- }
-
- public function setMaximumRows($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_maximumRows=$value;
- }
-
- public function getRetrieveTotalRowCount()
- {
- return $this->_retrieveTotalRowCount;
- }
-
- public function setRetrieveTotalRowCount($value)
- {
- $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
- }
-
- public function getTotalRowCount()
- {
- return $this->_totalRowCount;
- }
-
- public function setTotalRowCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_totalRowCount=$value;
- }
-}
-
-/**
- * TDataSourceView class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceView extends TComponent
-{
- private $_owner;
- private $_name;
-
- public function __construct(IDataSource $owner,$viewName)
- {
- $this->_owner=$owner;
- $this->_name=$viewName;
- }
-
- /**
- * Performs DB selection based on specified parameters.
- * @param ???
- * @return Traversable
- */
- abstract public function select($parameters);
-
- /**
- * Inserts a DB record.
- * @param array|TMap
- * @return integer affected rows
- */
- public function insertAt($values)
- {
- throw new TNotSupportedException('datasourceview_insert_unsupported');
- }
-
- /**
- * Updates DB record(s) with the specified keys and new values
- * @param array|TMap keys for specifying the records to be updated
- * @param array|TMap new values
- * @return integer affected rows
- */
- public function update($keys,$values)
- {
- throw new TNotSupportedException('datasourceview_update_unsupported');
- }
-
- /**
- * Deletes DB row(s) with the specified keys.
- * @param array|TMap keys for specifying the rows to be deleted
- * @return integer affected rows
- */
- public function delete($keys)
- {
- throw new TNotSupportedException('datasourceview_delete_unsupported');
- }
-
- public function getCanDelete()
- {
- return false;
- }
-
- public function getCanInsert()
- {
- return false;
- }
-
- public function getCanPage()
- {
- return false;
- }
-
- public function getCanGetRowCount()
- {
- return false;
- }
-
- public function getCanSort()
- {
- return false;
- }
-
- public function getCanUpdate()
- {
- return false;
- }
-
- public function getName()
- {
- return $this->_name;
- }
-
- public function getDataSource()
- {
- return $this->_owner;
- }
-
- public function onDataSourceViewChanged($param)
- {
- $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
- }
-}
-
-/**
- * TReadOnlyDataSourceView class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSourceView extends TDataSourceView
-{
- private $_dataSource=null;
-
- public function __construct(IDataSource $owner,$viewName,$dataSource)
- {
- parent::__construct($owner,$viewName);
- if($dataSource===null || is_array($dataSource))
- $this->_dataSource=new TMap($dataSource);
- else if($dataSource instanceof Traversable)
- $this->_dataSource=$dataSource;
- else
- throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
- }
-
- public function select($parameters)
- {
- return $this->_dataSource;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataSourceSelectParameters class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataSourceSelectParameters extends TComponent +{ + private $_retrieveTotalRowCount=false; + private $_startRowIndex=0; + private $_totalRowCount=0; + private $_maximumRows=0; + + public function getStartRowIndex() + { + return $this->_startRowIndex; + } + + public function setStartRowIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_startRowIndex=$value; + } + + public function getMaximumRows() + { + return $this->_maximumRows; + } + + public function setMaximumRows($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_maximumRows=$value; + } + + public function getRetrieveTotalRowCount() + { + return $this->_retrieveTotalRowCount; + } + + public function setRetrieveTotalRowCount($value) + { + $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value); + } + + public function getTotalRowCount() + { + return $this->_totalRowCount; + } + + public function setTotalRowCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=0; + $this->_totalRowCount=$value; + } +} + +/** + * TDataSourceView class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TDataSourceView extends TComponent +{ + private $_owner; + private $_name; + + public function __construct(IDataSource $owner,$viewName) + { + $this->_owner=$owner; + $this->_name=$viewName; + } + + /** + * Performs DB selection based on specified parameters. + * @param ??? + * @return Traversable + */ + abstract public function select($parameters); + + /** + * Inserts a DB record. + * @param array|TMap + * @return integer affected rows + */ + public function insertAt($values) + { + throw new TNotSupportedException('datasourceview_insert_unsupported'); + } + + /** + * Updates DB record(s) with the specified keys and new values + * @param array|TMap keys for specifying the records to be updated + * @param array|TMap new values + * @return integer affected rows + */ + public function update($keys,$values) + { + throw new TNotSupportedException('datasourceview_update_unsupported'); + } + + /** + * Deletes DB row(s) with the specified keys. + * @param array|TMap keys for specifying the rows to be deleted + * @return integer affected rows + */ + public function delete($keys) + { + throw new TNotSupportedException('datasourceview_delete_unsupported'); + } + + public function getCanDelete() + { + return false; + } + + public function getCanInsert() + { + return false; + } + + public function getCanPage() + { + return false; + } + + public function getCanGetRowCount() + { + return false; + } + + public function getCanSort() + { + return false; + } + + public function getCanUpdate() + { + return false; + } + + public function getName() + { + return $this->_name; + } + + public function getDataSource() + { + return $this->_owner; + } + + public function onDataSourceViewChanged($param) + { + $this->raiseEvent('OnDataSourceViewChanged',$this,$param); + } +} + +/** + * TReadOnlyDataSourceView class + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TReadOnlyDataSourceView extends TDataSourceView +{ + private $_dataSource=null; + + public function __construct(IDataSource $owner,$viewName,$dataSource) + { + parent::__construct($owner,$viewName); + if($dataSource===null || is_array($dataSource)) + $this->_dataSource=new TMap($dataSource); + else if($dataSource instanceof Traversable) + $this->_dataSource=$dataSource; + else + throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid'); + } + + public function select($parameters) + { + return $this->_dataSource; + } +} + diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php index 24372565..0e412e24 100644 --- a/framework/Web/UI/WebControls/TDataTypeValidator.php +++ b/framework/Web/UI/WebControls/TDataTypeValidator.php @@ -1,141 +1,141 @@ -<?php
-/**
- * TDataTypeValidator class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDataTypeValidator class. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TDataTypeValidator class
- *
- * TDataTypeValidator verifies if the input data is of the type specified
- * by {@link setDataType DataType}.
- * The following data types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type.
- * - <b>String</b> A string data type.
- * For <b>Date</b> type, the property {@link setDateFormat DateFormat}
- * will be used to determine how to parse the date string. If it is not
- * provided, the string will be assumed to be in GNU datetime format.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataTypeValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDataTypeValidator';
- }
-
- /**
- * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType','String');
- }
-
- /**
- * Sets the data type that the values being compared are converted to before the comparison is made.
- * @param TValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
-
- /**
- * Determine if the given value is of a particular type using RegExp.
- * @param string value to check
- * @return boolean true if value fits the type expression.
- */
- protected function evaluateDataTypeCheck($value)
- {
- if($value=='')
- return true;
-
- switch($this->getDataType())
- {
- case TValidationDataType::Integer:
- return preg_match('/^[-+]?[0-9]+$/',trim($value));
- case TValidationDataType::Float:
- return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
- case TValidationDataType::Date:
- $dateFormat = $this->getDateFormat();
- if(strlen($dateFormat))
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
- return $formatter->isValidDate($value);
- }
- else
- return strtotime($value) > 0;
- }
- return true;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['DataType']=$this->getDataType();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data is of valid type.
- * The validation always succeeds if ControlToValidate is not specified
- * or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
-
- return $this->evaluateDataTypeCheck($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TDataTypeValidator class + * + * TDataTypeValidator verifies if the input data is of the type specified + * by {@link setDataType DataType}. + * The following data types are supported: + * - <b>Integer</b> A 32-bit signed integer data type. + * - <b>Float</b> A double-precision floating point number data type. + * - <b>Date</b> A date data type. + * - <b>String</b> A string data type. + * For <b>Date</b> type, the property {@link setDateFormat DateFormat} + * will be used to determine how to parse the date string. If it is not + * provided, the string will be assumed to be in GNU datetime format. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDataTypeValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TDataTypeValidator'; + } + + /** + * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String. + */ + public function getDataType() + { + return $this->getViewState('DataType','String'); + } + + /** + * Sets the data type that the values being compared are converted to before the comparison is made. + * @param TValidationDataType the data type + */ + public function setDataType($value) + { + $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String); + } + + /** + * Sets the date format for a date validation + * @param string the date format value + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat', $value, ''); + } + + /** + * @return string the date validation date format if any + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat', ''); + } + + + /** + * Determine if the given value is of a particular type using RegExp. + * @param string value to check + * @return boolean true if value fits the type expression. + */ + protected function evaluateDataTypeCheck($value) + { + if($value=='') + return true; + + switch($this->getDataType()) + { + case TValidationDataType::Integer: + return preg_match('/^[-+]?[0-9]+$/',trim($value)); + case TValidationDataType::Float: + return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value)); + case TValidationDataType::Date: + $dateFormat = $this->getDateFormat(); + if(strlen($dateFormat)) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat); + return $formatter->isValidDate($value); + } + else + return strtotime($value) > 0; + } + return true; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $options['DataType']=$this->getDataType(); + if(($dateFormat=$this->getDateFormat())!=='') + $options['DateFormat']=$dateFormat; + return $options; + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input data is of valid type. + * The validation always succeeds if ControlToValidate is not specified + * or the input data is empty. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + if(($value=$this->getValidationValue($this->getValidationTarget()))==='') + return true; + + return $this->evaluateDataTypeCheck($value); + } +} + diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php index 8d1a811c..866bc585 100644 --- a/framework/Web/UI/WebControls/TDatePicker.php +++ b/framework/Web/UI/WebControls/TDatePicker.php @@ -1,993 +1,993 @@ -<?php
-/**
- * TDatePicker class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTextBox class
- */
-Prado::using('System.Web.UI.WebControls.TTextBox');
-
-/**
- *
- * TDatePicker class.
- *
- * TDatePicker displays a text box for date input purpose.
- * When the text box receives focus, a calendar will pop up and users can
- * pick up from it a date that will be automatically entered into the text box.
- * The format of the date string displayed in the text box is determined by
- * the <b>DateFormat</b> property. Valid formats are the combination of the
- * following tokens,
- *
- * <code>
- * Character Format Pattern (en-US)
- * -----------------------------------------
- * d day digit
- * dd padded day digit e.g. 01, 02
- * M month digit
- * MM padded month digit
- * MMMM localized month name, e.g. March, April
- * yy 2 digit year
- * yyyy 4 digit year
- * -----------------------------------------
- * </code>
- *
- * TDatePicker has four <b>Mode</b> to show the date picker popup.
- *
- * # <b>Basic</b> -- Only shows a text input, focusing on the input shows the
- * date picker. This way you can access the popup using only
- * the keyboard. Note that because of this, TAB-bing through
- * this control will automatically select the current date if
- * no previous date was selected. If you close the popup (eg.
- * pressing the ESC key) you'll need to un-focus and re-focus
- * the control again for the popup to reappear.
- * # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the
- * date picker. This mode solves the two small problems of the
- * Basic mode. It was first introduced in Prado 3.2.
- * # <b>Button</b> -- Shows a button next to the text input, clicking on the
- * button shows the date, button text can be by the
- * <b>ButtonText</b> property
- * # <b>ImageButton</b> -- Shows an image next to the text input, clicking on
- * the image shows the date picker, image source can be
- * change through the <b>ButtonImageUrl</b> property.
- *
- * The <b>CssClass</b> property can be used to override the css class name
- * for the date picker panel. <b>CalendarStyle</b> property sets the packages
- * styles available. E.g. <b>default</b>.
- *
- * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with
- * default as "TextBox".
- * In <b>DropDownList</b> mode, in addition to the popup date picker, three
- * drop down list (day, month and year) are presented to select the date .
- *
- * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default
- * as "Bottom". It specifies the position of the calendar popup, relative to the
- * input field.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Carl G. Mathisen <carlgmathisen@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDatePicker extends TTextBox
-{
- /**
- * Script path relative to the TClientScriptManager::SCRIPT_PATH
- */
- const SCRIPT_PATH = 'prado/datepicker';
-
- /**
- * @var TDatePickerClientScript validator client-script options.
- */
- private $_clientScript;
- /**
- * AutoPostBack is not supported.
- */
- public function setAutoPostBack($value)
- {
- throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
- get_class($this));
- }
-
- /**
- * @return string the format of the date string
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat','dd-MM-yyyy');
- }
-
- /**
- * Sets the format of the date string.
- * @param string the format of the date string
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
- }
-
- /**
- * @return boolean whether the calendar window should pop up when the control receives focus
- */
- public function getShowCalendar()
- {
- return $this->getViewState('ShowCalendar',true);
- }
-
- /**
- * Sets whether to pop up the calendar window when the control receives focus
- * @param boolean whether to show the calendar window
- */
- public function setShowCalendar($value)
- {
- $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Gets the current culture.
- * @return string current culture, e.g. en_AU.
- */
- public function getCulture()
- {
- return $this->getViewState('Culture', '');
- }
-
- /**
- * Sets the culture/language for the date picker.
- * @param string a culture string, e.g. en_AU.
- */
- public function setCulture($value)
- {
- $this->setViewState('Culture', $value, '');
- }
-
- /**
- * @param TDatePickerInputMode input method of date values
- */
- public function setInputMode($value)
- {
- $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
- }
-
- /**
- * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
- */
- public function getInputMode()
- {
- return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
- }
-
- /**
- * @param TDatePickerMode calendar UI mode
- */
- public function setMode($value)
- {
- $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
- }
-
- /**
- * @return TDatePickerMode current calendar UI mode.
- */
- public function getMode()
- {
- return $this->getViewState('Mode', TDatePickerMode::Basic);
- }
- /**
- * @param string the image url for "Image" UI mode.
- */
- public function setButtonImageUrl($value)
- {
- $this->setViewState('ImageUrl', $value, '');
- }
-
- /**
- * @return string the image url for "Image" UI mode.
- */
- public function getButtonImageUrl()
- {
- return $this->getViewState('ImageUrl', '');
- }
-
- /**
- * @param string set the calendar style
- */
- public function setCalendarStyle($value)
- {
- $this->setViewState('CalendarStyle', $value, 'default');
- }
-
- /**
- * @return string current calendar style
- */
- public function getCalendarStyle()
- {
- return $this->getViewState('CalendarStyle', 'default');
- }
-
- /**
- * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
- * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
- */
- public function setFirstDayOfWeek($value)
- {
- $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
- }
-
- /**
- * @return integer first day of the week
- */
- public function getFirstDayOfWeek()
- {
- return $this->getViewState('FirstDayOfWeek', 1);
- }
-
- /**
- * @return string text for the date picker button. Default is "...".
- */
- public function getButtonText()
- {
- return $this->getViewState('ButtonText', '...');
- }
-
- /**
- * @param string text for the date picker button
- */
- public function setButtonText($value)
- {
- $this->setViewState('ButtonText', $value, '...');
- }
-
- /**
- * @param integer date picker starting year, default is 2000.
- */
- public function setFromYear($value)
- {
- $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
- }
-
- /**
- * @return integer date picker starting year, default is -5 years
- */
- public function getFromYear()
- {
- return $this->getViewState('FromYear', intval(@date('Y'))-5);
- }
-
- /**
- * @param integer date picker ending year, default +10 years
- */
- public function setUpToYear($value)
- {
- $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
- }
-
- /**
- * @return integer date picker ending year, default +10 years
- */
- public function getUpToYear()
- {
- return $this->getViewState('UpToYear', intval(@date('Y'))+10);
- }
-
- /**
- * @param TDatePickerPositionMode calendar UI position
- */
- public function setPositionMode($value)
- {
- $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return TDatePickerPositionMode current calendar UI position.
- */
- public function getPositionMode()
- {
- return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
- */
- public function getTimeStamp()
- {
- if(trim($this->getText())==='')
- return null;
- else
- return $this->getTimeStampFromText();
- }
-
- /**
- * Sets the date for the date picker using timestamp.
- * @param float time stamp for the date picker
- */
- public function setTimeStamp($value)
- {
- if($value===null || (is_string($value) && trim($value)===''))
- $this->setText('');
- else
- {
- $date = TPropertyValue::ensureFloat($value);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
- $this->setText($formatter->format($date));
- }
- }
-
- /**
- * Returns the timestamp selected by the user.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getTimeStamp()}.
- * @return integer the timestamp of the TDatePicker control.
- * @see getTimeStamp
- * @since 3.1.2
- */
- public function getData()
- {
- return $this->getTimeStamp();
- }
-
- /**
- * Sets the timestamp represented by this control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setTimeStamp()}.
- * @param integer the timestamp of the TDatePicker control.
- * @see setTimeStamp
- * @since 3.1.2
- */
- public function setData($value)
- {
- $this->setTimeStamp($value);
- }
-
- /**
- * @return string the date string.
- */
- public function getDate()
- {
- return $this->getText();
- }
-
- /**
- * @param string date string
- */
- public function setDate($value)
- {
- $this->setText($value);
- }
-
- /**
- * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
- *
- * The date picker on the client-side supports the following events.
- * # <tt>OnDateChanged</tt> -- raised when the date is changed.
- *
- * You can attach custom javascript code to each of these events
- *
- * @return TDatePickerClientScript javascript validator event options.
- */
- public function getClientSide()
- {
- if($this->_clientScript===null)
- $this->_clientScript = $this->createClientScript();
- return $this->_clientScript;
- }
-
- /**
- * @return TDatePickerClientScript javascript validator event options.
- */
- protected function createClientScript()
- {
- return new TDatePickerClientScript;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return integer the interger timestamp if valid, otherwise the original text.
- */
- public function getValidationPropertyValue()
- {
- if(($text = $this->getText()) === '')
- return '';
- $date = $this->getTimeStamp();
- return $date == null ? $text : $date;
- }
-
- /**
- * Publish the date picker Css asset files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getInputMode() === TDatePickerInputMode::DropDownList)
- {
- $page = $this->getPage();
- $uniqueID = $this->getUniqueID();
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year');
- }
- $this->publishCalendarStyle();
- $this->registerCalendarClientScriptPre();
- }
-
- /**
- * Renders body content.
- * This method overrides parent implementation by adding
- * additional date picker button if Mode is Button or ImageButton.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- {
- parent::render($writer);
- $this->renderDatePickerButtons($writer);
- }
- else
- {
- $this->renderDropDownListCalendar($writer);
- if($this->hasDayPattern())
- {
- $this->registerCalendarClientScriptPost();
- $this->renderDatePickerButtons($writer);
- }
- }
- }
-
- /**
- * Renders the date picker popup buttons.
- */
- protected function renderDatePickerButtons($writer)
- {
- if($this->getShowCalendar())
- {
- switch ($this->getMode())
- {
- case TDatePickerMode::Button:
- $this->renderButtonDatePicker($writer);
- break;
- case TDatePickerMode::ImageButton :
- $this->renderImageButtonDatePicker($writer);
- break;
- }
- }
- }
-
- /**
- * Loads user input data. Override parent implementation, when InputMode
- * is DropDownList call getDateFromPostData to get date data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- return parent::loadPostData($key, $values);
- $value = $this->getDateFromPostData($key, $values);
- if(!$this->getReadOnly() && $this->getText()!==$value)
- {
- $this->setText($value);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Loads date from drop down list data.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return array the date selected
- */
- protected function getDateFromPostData($key, $values)
- {
- $date = @getdate();
-
- if(isset($values[$key.'$day']))
- $day = intval($values[$key.'$day']);
- else
- $day = $date['mday'];
-
- if(isset($values[$key.'$month']))
- $month = intval($values[$key.'$month']) + 1;
- else
- $month = $date['mon'];
-
- if(isset($values[$key.'$year']))
- $year = intval($values[$key.'$year']);
- else
- $year = $date['year'];
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
- //$date = @mktime(0, 0, 0, $month, $day, $year);
-
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
- return $formatter->format($date);
- }
-
- /**
- * Get javascript date picker options.
- * @return array date picker client-side options
- */
- protected function getDatePickerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['InputMode'] = $this->getInputMode();
- $options['Format'] = $this->getDateFormat();
- $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
- if(($cssClass=$this->getCssClass())!=='')
- $options['ClassName'] = $cssClass;
- $options['CalendarStyle'] = $this->getCalendarStyle();
- $options['FromYear'] = $this->getFromYear();
- $options['UpToYear'] = $this->getUpToYear();
- switch($this->getMode())
- {
- case TDatePickerMode::Basic:
- break;
- case TDatePickerMode::Clickable:
- $options['TriggerEvent'] = "click";
- break;
- default:
- $options['Trigger'] = $this->getDatePickerButtonID();
- break;
- }
- $options['PositionMode'] = $this->getPositionMode();
-
- $options = array_merge($options, $this->getCulturalOptions());
- if($this->_clientScript!==null)
- $options = array_merge($options,
- $this->_clientScript->getOptions()->toArray());
- return $options;
- }
-
- /**
- * Get javascript localization options, e.g. month and weekday names.
- * @return array localization options.
- */
- protected function getCulturalOptions()
- {
- if($this->getCurrentCulture() == 'en')
- return array();
-
- $date = $this->getLocalizedCalendarInfo();
- $options['MonthNames'] = $date->getMonthNames();
- $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
- $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
-
- return $options;
- }
-
- /**
- * @return string the current culture, falls back to application if culture is not set.
- */
- protected function getCurrentCulture()
- {
- $app = $this->getApplication()->getGlobalization(false);
- return $this->getCulture() == '' ?
- ($app ? $app->getCulture() : 'en') : $this->getCulture();
- }
-
- /**
- * @return DateTimeFormatInfo date time format information for the current culture.
- */
- protected function getLocalizedCalendarInfo()
- {
- //expensive operations
- $culture = $this->getCurrentCulture();
- Prado::using('System.I18N.core.DateTimeFormatInfo');
- $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
- return $info->getDateTimeFormat();
- }
-
- /**
- * Renders the drop down list date picker.
- */
- protected function renderDropDownListCalendar($writer)
- {
- if($this->getMode() == TDatePickerMode::Basic)
- $this->setMode(TDatePickerMode::ImageButton);
- parent::addAttributesToRender($writer);
- $writer->removeAttribute('name');
- $writer->removeAttribute('type');
- $writer->addAttribute('id', $this->getClientID());
-
- if(strlen($class = $this->getCssClass()) > 0)
- $writer->addAttribute('class', $class);
- $writer->renderBeginTag('span');
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getDate($this->getTimeStampFromText());
- //$date = @getdate($this->getTimeStampFromText());
-
- $this->renderCalendarSelections($writer, $date);
-
- //render a hidden input field
- $writer->addAttribute('name', $this->getUniqueID());
- $writer->addAttribute('type', 'hidden');
- $writer->addAttribute('value', $this->getText());
- $writer->renderBeginTag('input');
-
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
-
- protected function hasDayPattern()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- return ($formatter->getDayPattern()!==null);
- }
-
- /**
- * Renders the calendar drop down list depending on the DateFormat pattern.
- * @param THtmlWriter the Html writer to render the drop down lists.
- * @param array the current selected date
- */
- protected function renderCalendarSelections($writer, $date)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
-
- foreach($formatter->getDayMonthYearOrdering() as $type)
- {
- if($type == 'day')
- $this->renderCalendarDayOptions($writer,$date['mday']);
- elseif($type == 'month')
- $this->renderCalendarMonthOptions($writer,$date['mon']);
- elseif($type == 'year')
- $this->renderCalendarYearOptions($writer,$date['year']);
- }
- }
-
- /**
- * Gets the date from the text input using TSimpleDateFormatter
- * @return integer current selected date timestamp
- */
- protected function getTimeStampFromText()
- {
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
- return $formatter->parse($this->getText());
- }
-
- /**
- * Renders a drop down lists.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param array list of selection options
- * @param mixed selected key.
- */
- private function renderDropDownListOptions($writer,$options,$selected=null)
- {
- foreach($options as $k => $v)
- {
- $writer->addAttribute('value', $k);
- if($k == $selected)
- $writer->addAttribute('selected', 'selected');
- $writer->renderBeginTag('option');
- $writer->write($v);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the day drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected day.
- */
- protected function renderCalendarDayOptions($writer, $selected=null)
- {
- $days = $this->getDropDownDayOptions();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
- $writer->addAttribute('class', 'datepicker_day_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer, $days, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * @return array list of day options for a drop down list.
- */
- protected function getDropDownDayOptions()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- $days = array();
- $requiresPadding = $formatter->getDayPattern() === 'dd';
- for($i=1;$i<=31;$i++)
- {
- $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
- }
- return $days;
- }
-
- /**
- * Renders the month drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected month.
- */
- protected function renderCalendarMonthOptions($writer, $selected=null)
- {
- $info = $this->getLocalizedCalendarInfo();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
- $writer->addAttribute('class', 'datepicker_month_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer,
- $this->getLocalizedMonthNames($info), $selected-1);
- $writer->renderEndTag();
- }
-
- /**
- * Returns the localized month names that depends on the month format pattern.
- * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
- * and "M" return month digits.
- * @param DateTimeFormatInfo localized date format information.
- * @return array localized month names.
- */
- protected function getLocalizedMonthNames($info)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- switch($formatter->getMonthPattern())
- {
- case 'MMM': return $info->getAbbreviatedMonthNames();
- case 'MM':
- $array = array();
- for($i=1;$i<=12;$i++)
- $array[$i-1] = $i < 10 ? '0'.$i : $i;
- return $array;
- case 'M':
- $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
- return $array;
- default : return $info->getMonthNames();
- }
- }
-
- /**
- * Renders the year drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected year.
- */
- protected function renderCalendarYearOptions($writer, $selected=null)
- {
- $years = array();
- for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
- $years[$i] = $i;
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $writer->addAttribute('class', 'datepicker_year_options');
- $this->renderDropDownListOptions($writer, $years, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * Gets the ID for the date picker trigger button.
- * @return string unique button ID
- */
- protected function getDatePickerButtonID()
- {
- return $this->getClientID().'button';
- }
-
- /**
- * Adds an additional button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderButtonDatePicker($writer)
- {
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('type', 'button');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
- $writer->addAttribute('value',$this->getButtonText());
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag("input");
- $writer->renderEndTag();
- }
-
- /**
- * Adds an additional image button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderImageButtonDatePicker($writer)
- {
- $url = $this->getButtonImageUrl();
- $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('src', $url);
- $writer->addAttribute('alt', ' ');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->addAttribute('type', 'image');
- $writer->addAttribute('onclick', 'return false;');
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * @param string date picker asset file in the self::SCRIPT_PATH directory.
- * @return string date picker asset url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Publish the calendar style Css asset file.
- * @return string Css file url.
- */
- protected function publishCalendarStyle()
- {
- $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- return $url;
- }
-
- /**
- * Add the client id to the input textbox, and register the client scripts.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->registerCalendarClientScriptPost();
- }
-
-
- /**
- * Registers the javascript code to initialize the date picker.
- */
- protected function registerCalendarClientScriptPre()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPradoScript("datepicker");
- }
- }
-
- protected function registerCalendarClientScriptPost()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
- {
- $spacer = $this->getAssetUrl('spacer.gif');
- $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
- $cs->registerEndScript('TDatePicker.spacer', $code);
- }
-
- $options = TJavaScript::encode($this->getDatePickerOptions());
- $code = "new Prado.WebUI.TDatePicker($options);";
- $cs->registerEndScript("prado:".$this->getClientID(), $code);
- }
- }
-}
-
-/**
- * TDatePickerClientScript class.
- *
- * Client-side date picker event {@link setOnDateChanged OnDateChanged}
- * can be modified through the {@link TDatePicker::getClientSide ClientSide}
- * property of a date picker.
- *
- * The <tt>OnDateChanged</tt> event is raise when the date picker's date
- * is changed.
- * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
- * as parameter to this event
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerClientScript extends TClientSideOptions
-{
- /**
- * Javascript code to execute when the date picker's date is changed.
- * @param string javascript code
- */
- public function setOnDateChanged($javascript)
- {
- $this->setFunction('OnDateChanged', $javascript);
- }
-
- /**
- * @return string javascript code to execute when the date picker's date is changed.
- */
- public function getOnDateChanged()
- {
- return $this->getOption('OnDateChanged');
- }
-}
-
-
-/**
- * TDatePickerInputMode class.
- * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
- *
- * The following enumerable values are defined:
- * - TextBox: text boxes are used to input date values
- * - DropDownList: dropdown lists are used to pick up date values
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerInputMode extends TEnumerable
-{
- const TextBox='TextBox';
- const DropDownList='DropDownList';
-}
-
-/**
- * TDatePickerMode class.
- * TDatePickerMode defines the enumerable type for the possible UI mode
- * that a {@link TDatePicker} control can take.
- *
- * The following enumerable values are defined:
- * - Basic: Only shows a text input, focusing on the input shows the date picker
- * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
- * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
- * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerMode extends TEnumerable
-{
- const Basic='Basic';
- const Clickable='Clickable';
- const Button='Button';
- const ImageButton='ImageButton';
-}
-
-/**
- * TDatePickerPositionMode class.
- * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
- *
- * The following enumerable values are defined:
- * - Top: the date picker is placed above the input field
- * - Bottom: the date picker is placed below the input field
- *
- * @author Carl G. Mathisen <carlgmathisen@gmail.com>
- * @package System.Web.UI.WebControls
- * @since 3.1.4
- */
-class TDatePickerPositionMode extends TEnumerable
-{
- const Top='Top';
- const Bottom='Bottom';
-}
+<?php +/** + * TDatePicker class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTextBox class + */ +Prado::using('System.Web.UI.WebControls.TTextBox'); + +/** + * + * TDatePicker class. + * + * TDatePicker displays a text box for date input purpose. + * When the text box receives focus, a calendar will pop up and users can + * pick up from it a date that will be automatically entered into the text box. + * The format of the date string displayed in the text box is determined by + * the <b>DateFormat</b> property. Valid formats are the combination of the + * following tokens, + * + * <code> + * Character Format Pattern (en-US) + * ----------------------------------------- + * d day digit + * dd padded day digit e.g. 01, 02 + * M month digit + * MM padded month digit + * MMMM localized month name, e.g. March, April + * yy 2 digit year + * yyyy 4 digit year + * ----------------------------------------- + * </code> + * + * TDatePicker has four <b>Mode</b> to show the date picker popup. + * + * # <b>Basic</b> -- Only shows a text input, focusing on the input shows the + * date picker. This way you can access the popup using only + * the keyboard. Note that because of this, TAB-bing through + * this control will automatically select the current date if + * no previous date was selected. If you close the popup (eg. + * pressing the ESC key) you'll need to un-focus and re-focus + * the control again for the popup to reappear. + * # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the + * date picker. This mode solves the two small problems of the + * Basic mode. It was first introduced in Prado 3.2. + * # <b>Button</b> -- Shows a button next to the text input, clicking on the + * button shows the date, button text can be by the + * <b>ButtonText</b> property + * # <b>ImageButton</b> -- Shows an image next to the text input, clicking on + * the image shows the date picker, image source can be + * change through the <b>ButtonImageUrl</b> property. + * + * The <b>CssClass</b> property can be used to override the css class name + * for the date picker panel. <b>CalendarStyle</b> property sets the packages + * styles available. E.g. <b>default</b>. + * + * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with + * default as "TextBox". + * In <b>DropDownList</b> mode, in addition to the popup date picker, three + * drop down list (day, month and year) are presented to select the date . + * + * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default + * as "Bottom". It specifies the position of the calendar popup, relative to the + * input field. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @author Carl G. Mathisen <carlgmathisen@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDatePicker extends TTextBox +{ + /** + * Script path relative to the TClientScriptManager::SCRIPT_PATH + */ + const SCRIPT_PATH = 'prado/datepicker'; + + /** + * @var TDatePickerClientScript validator client-script options. + */ + private $_clientScript; + /** + * AutoPostBack is not supported. + */ + public function setAutoPostBack($value) + { + throw new TNotSupportedException('tdatepicker_autopostback_unsupported', + get_class($this)); + } + + /** + * @return string the format of the date string + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat','dd-MM-yyyy'); + } + + /** + * Sets the format of the date string. + * @param string the format of the date string + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat',$value,'dd-MM-yyyy'); + } + + /** + * @return boolean whether the calendar window should pop up when the control receives focus + */ + public function getShowCalendar() + { + return $this->getViewState('ShowCalendar',true); + } + + /** + * Sets whether to pop up the calendar window when the control receives focus + * @param boolean whether to show the calendar window + */ + public function setShowCalendar($value) + { + $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Gets the current culture. + * @return string current culture, e.g. en_AU. + */ + public function getCulture() + { + return $this->getViewState('Culture', ''); + } + + /** + * Sets the culture/language for the date picker. + * @param string a culture string, e.g. en_AU. + */ + public function setCulture($value) + { + $this->setViewState('Culture', $value, ''); + } + + /** + * @param TDatePickerInputMode input method of date values + */ + public function setInputMode($value) + { + $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox); + } + + /** + * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox. + */ + public function getInputMode() + { + return $this->getViewState('InputMode', TDatePickerInputMode::TextBox); + } + + /** + * @param TDatePickerMode calendar UI mode + */ + public function setMode($value) + { + $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic); + } + + /** + * @return TDatePickerMode current calendar UI mode. + */ + public function getMode() + { + return $this->getViewState('Mode', TDatePickerMode::Basic); + } + /** + * @param string the image url for "Image" UI mode. + */ + public function setButtonImageUrl($value) + { + $this->setViewState('ImageUrl', $value, ''); + } + + /** + * @return string the image url for "Image" UI mode. + */ + public function getButtonImageUrl() + { + return $this->getViewState('ImageUrl', ''); + } + + /** + * @param string set the calendar style + */ + public function setCalendarStyle($value) + { + $this->setViewState('CalendarStyle', $value, 'default'); + } + + /** + * @return string current calendar style + */ + public function getCalendarStyle() + { + return $this->getViewState('CalendarStyle', 'default'); + } + + /** + * Set the first day of week, with 0 as Sunday, 1 as Monday, etc. + * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc. + */ + public function setFirstDayOfWeek($value) + { + $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1); + } + + /** + * @return integer first day of the week + */ + public function getFirstDayOfWeek() + { + return $this->getViewState('FirstDayOfWeek', 1); + } + + /** + * @return string text for the date picker button. Default is "...". + */ + public function getButtonText() + { + return $this->getViewState('ButtonText', '...'); + } + + /** + * @param string text for the date picker button + */ + public function setButtonText($value) + { + $this->setViewState('ButtonText', $value, '...'); + } + + /** + * @param integer date picker starting year, default is 2000. + */ + public function setFromYear($value) + { + $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5); + } + + /** + * @return integer date picker starting year, default is -5 years + */ + public function getFromYear() + { + return $this->getViewState('FromYear', intval(@date('Y'))-5); + } + + /** + * @param integer date picker ending year, default +10 years + */ + public function setUpToYear($value) + { + $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10); + } + + /** + * @return integer date picker ending year, default +10 years + */ + public function getUpToYear() + { + return $this->getViewState('UpToYear', intval(@date('Y'))+10); + } + + /** + * @param TDatePickerPositionMode calendar UI position + */ + public function setPositionMode($value) + { + $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom); + } + + /** + * @return TDatePickerPositionMode current calendar UI position. + */ + public function getPositionMode() + { + return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom); + } + + /** + * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously. + */ + public function getTimeStamp() + { + if(trim($this->getText())==='') + return null; + else + return $this->getTimeStampFromText(); + } + + /** + * Sets the date for the date picker using timestamp. + * @param float time stamp for the date picker + */ + public function setTimeStamp($value) + { + if($value===null || (is_string($value) && trim($value)==='')) + $this->setText(''); + else + { + $date = TPropertyValue::ensureFloat($value); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat()); + $this->setText($formatter->format($date)); + } + } + + /** + * Returns the timestamp selected by the user. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getTimeStamp()}. + * @return integer the timestamp of the TDatePicker control. + * @see getTimeStamp + * @since 3.1.2 + */ + public function getData() + { + return $this->getTimeStamp(); + } + + /** + * Sets the timestamp represented by this control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setTimeStamp()}. + * @param integer the timestamp of the TDatePicker control. + * @see setTimeStamp + * @since 3.1.2 + */ + public function setData($value) + { + $this->setTimeStamp($value); + } + + /** + * @return string the date string. + */ + public function getDate() + { + return $this->getText(); + } + + /** + * @param string date string + */ + public function setDate($value) + { + $this->setText($value); + } + + /** + * Gets the TDatePickerClientScript to set the TDatePicker event handlers. + * + * The date picker on the client-side supports the following events. + * # <tt>OnDateChanged</tt> -- raised when the date is changed. + * + * You can attach custom javascript code to each of these events + * + * @return TDatePickerClientScript javascript validator event options. + */ + public function getClientSide() + { + if($this->_clientScript===null) + $this->_clientScript = $this->createClientScript(); + return $this->_clientScript; + } + + /** + * @return TDatePickerClientScript javascript validator event options. + */ + protected function createClientScript() + { + return new TDatePickerClientScript; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return integer the interger timestamp if valid, otherwise the original text. + */ + public function getValidationPropertyValue() + { + if(($text = $this->getText()) === '') + return ''; + $date = $this->getTimeStamp(); + return $date == null ? $text : $date; + } + + /** + * Publish the date picker Css asset files. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getInputMode() === TDatePickerInputMode::DropDownList) + { + $page = $this->getPage(); + $uniqueID = $this->getUniqueID(); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day'); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month'); + $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year'); + } + $this->publishCalendarStyle(); + $this->registerCalendarClientScriptPre(); + } + + /** + * Renders body content. + * This method overrides parent implementation by adding + * additional date picker button if Mode is Button or ImageButton. + * @param THtmlWriter writer + */ + public function render($writer) + { + if($this->getInputMode() == TDatePickerInputMode::TextBox) + { + parent::render($writer); + $this->renderDatePickerButtons($writer); + } + else + { + $this->renderDropDownListCalendar($writer); + if($this->hasDayPattern()) + { + $this->registerCalendarClientScriptPost(); + $this->renderDatePickerButtons($writer); + } + } + } + + /** + * Renders the date picker popup buttons. + */ + protected function renderDatePickerButtons($writer) + { + if($this->getShowCalendar()) + { + switch ($this->getMode()) + { + case TDatePickerMode::Button: + $this->renderButtonDatePicker($writer); + break; + case TDatePickerMode::ImageButton : + $this->renderImageButtonDatePicker($writer); + break; + } + } + } + + /** + * Loads user input data. Override parent implementation, when InputMode + * is DropDownList call getDateFromPostData to get date data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + if($this->getInputMode() == TDatePickerInputMode::TextBox) + return parent::loadPostData($key, $values); + $value = $this->getDateFromPostData($key, $values); + if(!$this->getReadOnly() && $this->getText()!==$value) + { + $this->setText($value); + return true; + } + else + return false; + } + + /** + * Loads date from drop down list data. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return array the date selected + */ + protected function getDateFromPostData($key, $values) + { + $date = @getdate(); + + if(isset($values[$key.'$day'])) + $day = intval($values[$key.'$day']); + else + $day = $date['mday']; + + if(isset($values[$key.'$month'])) + $month = intval($values[$key.'$month']) + 1; + else + $month = $date['mon']; + + if(isset($values[$key.'$year'])) + $year = intval($values[$key.'$year']); + else + $year = $date['year']; + + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year); + //$date = @mktime(0, 0, 0, $month, $day, $year); + + $pattern = $this->getDateFormat(); + $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern); + return $formatter->format($date); + } + + /** + * Get javascript date picker options. + * @return array date picker client-side options + */ + protected function getDatePickerOptions() + { + $options['ID'] = $this->getClientID(); + $options['InputMode'] = $this->getInputMode(); + $options['Format'] = $this->getDateFormat(); + $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek(); + if(($cssClass=$this->getCssClass())!=='') + $options['ClassName'] = $cssClass; + $options['CalendarStyle'] = $this->getCalendarStyle(); + $options['FromYear'] = $this->getFromYear(); + $options['UpToYear'] = $this->getUpToYear(); + switch($this->getMode()) + { + case TDatePickerMode::Basic: + break; + case TDatePickerMode::Clickable: + $options['TriggerEvent'] = "click"; + break; + default: + $options['Trigger'] = $this->getDatePickerButtonID(); + break; + } + $options['PositionMode'] = $this->getPositionMode(); + + $options = array_merge($options, $this->getCulturalOptions()); + if($this->_clientScript!==null) + $options = array_merge($options, + $this->_clientScript->getOptions()->toArray()); + return $options; + } + + /** + * Get javascript localization options, e.g. month and weekday names. + * @return array localization options. + */ + protected function getCulturalOptions() + { + if($this->getCurrentCulture() == 'en') + return array(); + + $date = $this->getLocalizedCalendarInfo(); + $options['MonthNames'] = $date->getMonthNames(); + $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames(); + $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames(); + + return $options; + } + + /** + * @return string the current culture, falls back to application if culture is not set. + */ + protected function getCurrentCulture() + { + $app = $this->getApplication()->getGlobalization(false); + return $this->getCulture() == '' ? + ($app ? $app->getCulture() : 'en') : $this->getCulture(); + } + + /** + * @return DateTimeFormatInfo date time format information for the current culture. + */ + protected function getLocalizedCalendarInfo() + { + //expensive operations + $culture = $this->getCurrentCulture(); + Prado::using('System.I18N.core.DateTimeFormatInfo'); + $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture); + return $info->getDateTimeFormat(); + } + + /** + * Renders the drop down list date picker. + */ + protected function renderDropDownListCalendar($writer) + { + if($this->getMode() == TDatePickerMode::Basic) + $this->setMode(TDatePickerMode::ImageButton); + parent::addAttributesToRender($writer); + $writer->removeAttribute('name'); + $writer->removeAttribute('type'); + $writer->addAttribute('id', $this->getClientID()); + + if(strlen($class = $this->getCssClass()) > 0) + $writer->addAttribute('class', $class); + $writer->renderBeginTag('span'); + + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getDate($this->getTimeStampFromText()); + //$date = @getdate($this->getTimeStampFromText()); + + $this->renderCalendarSelections($writer, $date); + + //render a hidden input field + $writer->addAttribute('name', $this->getUniqueID()); + $writer->addAttribute('type', 'hidden'); + $writer->addAttribute('value', $this->getText()); + $writer->renderBeginTag('input'); + + $writer->renderEndTag(); + $writer->renderEndTag(); + } + + protected function hasDayPattern() + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + return ($formatter->getDayPattern()!==null); + } + + /** + * Renders the calendar drop down list depending on the DateFormat pattern. + * @param THtmlWriter the Html writer to render the drop down lists. + * @param array the current selected date + */ + protected function renderCalendarSelections($writer, $date) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + + foreach($formatter->getDayMonthYearOrdering() as $type) + { + if($type == 'day') + $this->renderCalendarDayOptions($writer,$date['mday']); + elseif($type == 'month') + $this->renderCalendarMonthOptions($writer,$date['mon']); + elseif($type == 'year') + $this->renderCalendarYearOptions($writer,$date['year']); + } + } + + /** + * Gets the date from the text input using TSimpleDateFormatter + * @return integer current selected date timestamp + */ + protected function getTimeStampFromText() + { + $pattern = $this->getDateFormat(); + $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern); + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern); + return $formatter->parse($this->getText()); + } + + /** + * Renders a drop down lists. + * @param THtmlWriter the writer used for the rendering purpose + * @param array list of selection options + * @param mixed selected key. + */ + private function renderDropDownListOptions($writer,$options,$selected=null) + { + foreach($options as $k => $v) + { + $writer->addAttribute('value', $k); + if($k == $selected) + $writer->addAttribute('selected', 'selected'); + $writer->renderBeginTag('option'); + $writer->write($v); + $writer->renderEndTag(); + } + } + + /** + * Renders the day drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected day. + */ + protected function renderCalendarDayOptions($writer, $selected=null) + { + $days = $this->getDropDownDayOptions(); + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day'); + $writer->addAttribute('class', 'datepicker_day_options'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $this->renderDropDownListOptions($writer, $days, $selected); + $writer->renderEndTag(); + } + + /** + * @return array list of day options for a drop down list. + */ + protected function getDropDownDayOptions() + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + $days = array(); + $requiresPadding = $formatter->getDayPattern() === 'dd'; + for($i=1;$i<=31;$i++) + { + $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i; + } + return $days; + } + + /** + * Renders the month drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected month. + */ + protected function renderCalendarMonthOptions($writer, $selected=null) + { + $info = $this->getLocalizedCalendarInfo(); + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month'); + $writer->addAttribute('class', 'datepicker_month_options'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $this->renderDropDownListOptions($writer, + $this->getLocalizedMonthNames($info), $selected-1); + $writer->renderEndTag(); + } + + /** + * Returns the localized month names that depends on the month format pattern. + * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names + * and "M" return month digits. + * @param DateTimeFormatInfo localized date format information. + * @return array localized month names. + */ + protected function getLocalizedMonthNames($info) + { + $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', + $this->getDateFormat()); + switch($formatter->getMonthPattern()) + { + case 'MMM': return $info->getAbbreviatedMonthNames(); + case 'MM': + $array = array(); + for($i=1;$i<=12;$i++) + $array[$i-1] = $i < 10 ? '0'.$i : $i; + return $array; + case 'M': + $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i; + return $array; + default : return $info->getMonthNames(); + } + } + + /** + * Renders the year drop down list options. + * @param THtmlWriter the writer used for the rendering purpose + * @param mixed selected year. + */ + protected function renderCalendarYearOptions($writer, $selected=null) + { + $years = array(); + for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++) + $years[$i] = $i; + $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year'); + $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year'); + if($this->getReadOnly() || !$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag('select'); + $writer->addAttribute('class', 'datepicker_year_options'); + $this->renderDropDownListOptions($writer, $years, $selected); + $writer->renderEndTag(); + } + + /** + * Gets the ID for the date picker trigger button. + * @return string unique button ID + */ + protected function getDatePickerButtonID() + { + return $this->getClientID().'button'; + } + + /** + * Adds an additional button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ + protected function renderButtonDatePicker($writer) + { + $writer->addAttribute('id', $this->getDatePickerButtonID()); + $writer->addAttribute('type', 'button'); + $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton'); + $writer->addAttribute('value',$this->getButtonText()); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->renderBeginTag("input"); + $writer->renderEndTag(); + } + + /** + * Adds an additional image button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ + protected function renderImageButtonDatePicker($writer) + { + $url = $this->getButtonImageUrl(); + $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url; + $writer->addAttribute('id', $this->getDatePickerButtonID()); + $writer->addAttribute('src', $url); + $writer->addAttribute('alt', ' '); + $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton'); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled', 'disabled'); + $writer->addAttribute('type', 'image'); + $writer->addAttribute('onclick', 'return false;'); + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * @param string date picker asset file in the self::SCRIPT_PATH directory. + * @return string date picker asset url. + */ + protected function getAssetUrl($file='') + { + $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl(); + return $base.'/'.self::SCRIPT_PATH.'/'.$file; + } + + /** + * Publish the calendar style Css asset file. + * @return string Css file url. + */ + protected function publishCalendarStyle() + { + $url = $this->getAssetUrl($this->getCalendarStyle().'.css'); + $cs = $this->getPage()->getClientScript(); + if(!$cs->isStyleSheetFileRegistered($url)) + $cs->registerStyleSheetFile($url, $url); + return $url; + } + + /** + * Add the client id to the input textbox, and register the client scripts. + * @param THtmlWriter writer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + $this->registerCalendarClientScriptPost(); + } + + + /** + * Registers the javascript code to initialize the date picker. + */ + protected function registerCalendarClientScriptPre() + { + if($this->getShowCalendar()) + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPradoScript("datepicker"); + } + } + + protected function registerCalendarClientScriptPost() + { + if($this->getShowCalendar()) + { + $cs = $this->getPage()->getClientScript(); + if(!$cs->isEndScriptRegistered('TDatePicker.spacer')) + { + $spacer = $this->getAssetUrl('spacer.gif'); + $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';"; + $cs->registerEndScript('TDatePicker.spacer', $code); + } + + $options = TJavaScript::encode($this->getDatePickerOptions()); + $code = "new Prado.WebUI.TDatePicker($options);"; + $cs->registerEndScript("prado:".$this->getClientID(), $code); + } + } +} + +/** + * TDatePickerClientScript class. + * + * Client-side date picker event {@link setOnDateChanged OnDateChanged} + * can be modified through the {@link TDatePicker::getClientSide ClientSide} + * property of a date picker. + * + * The <tt>OnDateChanged</tt> event is raise when the date picker's date + * is changed. + * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent + * as parameter to this event + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerClientScript extends TClientSideOptions +{ + /** + * Javascript code to execute when the date picker's date is changed. + * @param string javascript code + */ + public function setOnDateChanged($javascript) + { + $this->setFunction('OnDateChanged', $javascript); + } + + /** + * @return string javascript code to execute when the date picker's date is changed. + */ + public function getOnDateChanged() + { + return $this->getOption('OnDateChanged'); + } +} + + +/** + * TDatePickerInputMode class. + * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods. + * + * The following enumerable values are defined: + * - TextBox: text boxes are used to input date values + * - DropDownList: dropdown lists are used to pick up date values + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerInputMode extends TEnumerable +{ + const TextBox='TextBox'; + const DropDownList='DropDownList'; +} + +/** + * TDatePickerMode class. + * TDatePickerMode defines the enumerable type for the possible UI mode + * that a {@link TDatePicker} control can take. + * + * The following enumerable values are defined: + * - Basic: Only shows a text input, focusing on the input shows the date picker + * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2) + * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the + * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker, + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDatePickerMode extends TEnumerable +{ + const Basic='Basic'; + const Clickable='Clickable'; + const Button='Button'; + const ImageButton='ImageButton'; +} + +/** + * TDatePickerPositionMode class. + * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input. + * + * The following enumerable values are defined: + * - Top: the date picker is placed above the input field + * - Bottom: the date picker is placed below the input field + * + * @author Carl G. Mathisen <carlgmathisen@gmail.com> + * @package System.Web.UI.WebControls + * @since 3.1.4 + */ +class TDatePickerPositionMode extends TEnumerable +{ + const Top='Top'; + const Bottom='Bottom'; +} diff --git a/framework/Web/UI/WebControls/TDropDownList.php b/framework/Web/UI/WebControls/TDropDownList.php index 0eba6285..57f1f165 100644 --- a/framework/Web/UI/WebControls/TDropDownList.php +++ b/framework/Web/UI/WebControls/TDropDownList.php @@ -1,154 +1,154 @@ -<?php
-/**
- * TDropDownList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TDropDownList class
- *
- * TDropDownList displays a dropdown list on a Web page.
- * It inherits all properties and events from {@link TListControl}.
- *
- * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
- * a list item, set a Group attribute with it,
- * <code>
- * $listitem->Attributes->Group="Group Name";
- * // or <com:TListItem Attributes.Group="Group Name" .../> in template
- * </code>
- *
- * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
- * displayed as the first list item by specifying either {@link setPromptText PromptText} or
- * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
- *
- * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
- * property is not affected by a prompt item: the items list will still be zero-based.
- *
- * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
- * available item in the dropdown list will be selected.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
-{
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('name',$this->getUniqueID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDropDownList';
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if(!$this->getEnabled(true))
- return false;
- $this->ensureDataBound();
- $selection=isset($values[$key])?$values[$key]:null;
- if($selection!==null)
- {
- $index=$this->getItems()->findIndexByValue($selection,false);
- if($this->getSelectedIndex()!==$index)
- {
- $this->setSelectedIndex($index);
- return $this->_dataChanged=true;
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndices($indices)
- {
- throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+<?php +/** + * TDropDownList class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * TDropDownList class + * + * TDropDownList displays a dropdown list on a Web page. + * It inherits all properties and events from {@link TListControl}. + * + * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for + * a list item, set a Group attribute with it, + * <code> + * $listitem->Attributes->Group="Group Name"; + * // or <com:TListItem Attributes.Group="Group Name" .../> in template + * </code> + * + * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be + * displayed as the first list item by specifying either {@link setPromptText PromptText} or + * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList. + * + * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex} + * property is not affected by a prompt item: the items list will still be zero-based. + * + * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first + * available item in the dropdown list will be selected. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable +{ + private $_dataChanged=false; + private $_isValid=true; + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + $writer->addAttribute('name',$this->getUniqueID()); + parent::addAttributesToRender($writer); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TDropDownList'; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + if(!$this->getEnabled(true)) + return false; + $this->ensureDataBound(); + $selection=isset($values[$key])?$values[$key]:null; + if($selection!==null) + { + $index=$this->getItems()->findIndexByValue($selection,false); + if($this->getSelectedIndex()!==$index) + { + $this->setSelectedIndex($index); + return $this->_dataChanged=true; + } + } + return false; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onSelectedIndexChanged(null); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * @throws TNotSupportedException if this method is invoked + */ + public function setSelectedIndices($indices) + { + throw new TNotSupportedException('dropdownlist_selectedindices_unsupported'); + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getSelectedValue(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } +} diff --git a/framework/Web/UI/WebControls/TDropDownListColumn.php b/framework/Web/UI/WebControls/TDropDownListColumn.php index ffbe8f70..941a9be1 100644 --- a/framework/Web/UI/WebControls/TDropDownListColumn.php +++ b/framework/Web/UI/WebControls/TDropDownListColumn.php @@ -1,321 +1,321 @@ -<?php
-/**
- * TDropDownListColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TDropDownListColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-Prado::using('System.Web.UI.WebControls.TDropDownList');
-
-/**
- * TDropDownListColumn class
- *
- * TDropDownListColumn represents a column that is bound to a field in a data source.
- * The cells in the column will be displayed using the data indexed by
- * {@link setDataTextField DataTextField}. You can customize the display by
- * setting {@link setDataTextFormatString DataTextFormatString}.
- *
- * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
- * with dropdown lists. Otherwise, a static text is displayed.
- * The currently selected dropndown list item is specified by the data indexed with
- * {@link setDataValueField DataValueField}.
- *
- * There are two approaches to specify the list items available for selection.
- * The first approach uses template syntax as follows,
- * <code>
- * <com:TDropDownListColumn ....>
- * <com:TListItem Value="1" Text="first item" />
- * <com:TListItem Value="2" Text="second item" />
- * <com:TListItem Value="3" Text="third item" />
- * </com:TDropDownListColumn>
- * </code>
- * The second approach specifies a data source to be bound to the dropdown lists
- * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
- * you may also want to specify which data fields are used for item values and texts
- * by setting {@link setListValueField ListValueField} and
- * {@link setListTextField ListTextField}, respectively.
- * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
- * Note, if you specify {@link setListDataSource ListDataSource}, do it before
- * calling the datagrid's dataBind().
- *
- * The dropdown list control in the TDropDownListColumn can be accessed by one of
- * the following two methods:
- * <code>
- * $datagridItem->DropDownListColumnID->DropDownList
- * $datagridItem->DropDownListColumnID->Controls[0]
- * </code>
- * The second method is possible because the dropdown list control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDropDownListColumn extends TDataGridColumn
-{
- private $_stateLoaded=false;
- private $_dataBound=false;
- private $_listControl=null;
-
- public function __construct()
- {
- $this->_listControl=new TDropDownList;
- }
-
- /**
- * Loads items from viewstate.
- * This method overrides the parent implementation by loading list items
- * @param mixed state values
- */
- public function loadState($state)
- {
- parent::loadState($state);
- $this->_stateLoaded=true;
- if(!$this->_dataBound)
- $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
- }
-
- /**
- * Saves items into viewstate.
- * This method overrides the parent implementation by saving list items
- */
- public function saveState()
- {
- $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
- return parent::saveState();
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- // Do not add items from template if items are loaded from viewstate
- if(!$this->_stateLoaded && ($object instanceof TListItem))
- {
- $object->setSelected(false);
- $index=$this->_listControl->getItems()->add($object);
- }
- }
-
- /**
- * @return string the field of the data source that provides the text content of the column.
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * Sets the field of the data source that provides the text content of the column.
- * If this is not set, the data specified via {@link getDataValueField DataValueField}
- * will be displayed in the column.
- * @param string the field of the data source that provides the text content of the column.
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function getDataValueField()
- {
- return $this->getViewState('DataValueField','');
- }
-
- /**
- * Sets the field of the data source that provides the key selecting an item in dropdown list.
- * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
- * applying the formatting string) will be used for selection, instead.
- * @param string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function setDataValueField($value)
- {
- $this->setViewState('DataValueField',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return Traversable data source to be bound to the dropdown list boxes.
- */
- public function getListDataSource()
- {
- return $this->_listControl->getDataSource();
- }
-
- /**
- * @param Traversable|array|string data source to be bound to the dropdown list boxes.
- */
- public function setListDataSource($value)
- {
- $this->_listControl->setDataSource($value);
- }
-
- /**
- * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
- */
- public function getListValueField()
- {
- return $this->getViewState('ListValueField','');
- }
-
- /**
- * @param string the data field used to populate the values of the dropdown list items
- */
- public function setListValueField($value)
- {
- $this->setViewState('ListValueField',$value,'');
- }
-
- /**
- * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
- */
- public function getListTextField()
- {
- return $this->getViewState('ListTextField','');
- }
-
- /**
- * @param string the data field used to populate the texts of the dropdown list items
- */
- public function setListTextField($value)
- {
- $this->setViewState('ListTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the list item texts will be displayed.
- */
- public function getListTextFormatString()
- {
- return $this->getViewState('ListTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the list item texts will be displayed.
- */
- public function setListTextFormatString($value)
- {
- $this->setViewState('ListTextFormatString',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a textbox for item in edit mode and the column is not read-only.
- * Otherwise it displays a static text.
- * The caption of the button and the static text are retrieved
- * from the datasource.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
- {
- $this->_listControl->setDataTextField($this->getListTextField());
- $this->_listControl->setDataValueField($this->getListValueField());
- $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
- $this->_listControl->dataBind();
- $this->_dataBound=true;
- }
- switch($itemType)
- {
- case TListItemType::EditItem:
- if(!$this->getReadOnly())
- {
- $listControl=clone $this->_listControl;
- $cell->getControls()->add($listControl);
- $cell->registerObject('DropDownList',$listControl);
- $control=$listControl;
- }
- else
- $control=$cell;
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
- $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- default:
- parent::initializeCell($cell,$columnIndex,$itemType);
- break;
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($valueField=$this->getDataValueField())!=='')
- $value=$this->getDataFieldValue($data,$valueField);
- else
- $value='';
- if(($textField=$this->getDataTextField())!=='')
- {
- $text=$this->getDataFieldValue($data,$textField);
- if($valueField==='')
- $value=$text;
- $formatString=$this->getDataTextFormatString();
- $text=$this->formatDataValue($formatString,$text);
- }
- else
- $text=$value;
- if($sender instanceof TTableCell)
- $sender->setText($text);
- else if($sender instanceof TDropDownList)
- $sender->setSelectedValue($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +Prado::using('System.Web.UI.WebControls.TDropDownList'); + +/** + * TDropDownListColumn class + * + * TDropDownListColumn represents a column that is bound to a field in a data source. + * The cells in the column will be displayed using the data indexed by + * {@link setDataTextField DataTextField}. You can customize the display by + * setting {@link setDataTextFormatString DataTextFormatString}. + * + * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode + * with dropdown lists. Otherwise, a static text is displayed. + * The currently selected dropndown list item is specified by the data indexed with + * {@link setDataValueField DataValueField}. + * + * There are two approaches to specify the list items available for selection. + * The first approach uses template syntax as follows, + * <code> + * <com:TDropDownListColumn ....> + * <com:TListItem Value="1" Text="first item" /> + * <com:TListItem Value="2" Text="second item" /> + * <com:TListItem Value="3" Text="third item" /> + * </com:TDropDownListColumn> + * </code> + * The second approach specifies a data source to be bound to the dropdown lists + * by setting {@link setListDataSource ListDataSource}. Like generic list controls, + * you may also want to specify which data fields are used for item values and texts + * by setting {@link setListValueField ListValueField} and + * {@link setListTextField ListTextField}, respectively. + * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}. + * Note, if you specify {@link setListDataSource ListDataSource}, do it before + * calling the datagrid's dataBind(). + * + * The dropdown list control in the TDropDownListColumn can be accessed by one of + * the following two methods: + * <code> + * $datagridItem->DropDownListColumnID->DropDownList + * $datagridItem->DropDownListColumnID->Controls[0] + * </code> + * The second method is possible because the dropdown list control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TDropDownListColumn extends TDataGridColumn +{ + private $_stateLoaded=false; + private $_dataBound=false; + private $_listControl=null; + + public function __construct() + { + $this->_listControl=new TDropDownList; + } + + /** + * Loads items from viewstate. + * This method overrides the parent implementation by loading list items + * @param mixed state values + */ + public function loadState($state) + { + parent::loadState($state); + $this->_stateLoaded=true; + if(!$this->_dataBound) + $this->_listControl->getItems()->loadState($this->getViewState('Items',null)); + } + + /** + * Saves items into viewstate. + * This method overrides the parent implementation by saving list items + */ + public function saveState() + { + $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null); + return parent::saveState(); + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TListItem} objects into the {@link getItems Items} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + // Do not add items from template if items are loaded from viewstate + if(!$this->_stateLoaded && ($object instanceof TListItem)) + { + $object->setSelected(false); + $index=$this->_listControl->getItems()->add($object); + } + } + + /** + * @return string the field of the data source that provides the text content of the column. + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * Sets the field of the data source that provides the text content of the column. + * If this is not set, the data specified via {@link getDataValueField DataValueField} + * will be displayed in the column. + * @param string the field of the data source that provides the text content of the column. + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the bound data will be displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the bound data will be displayed. + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string the field of the data source that provides the key selecting an item in dropdown list. + */ + public function getDataValueField() + { + return $this->getViewState('DataValueField',''); + } + + /** + * Sets the field of the data source that provides the key selecting an item in dropdown list. + * If this is not present, the data specified via {@link getDataTextField DataTextField} (without + * applying the formatting string) will be used for selection, instead. + * @param string the field of the data source that provides the key selecting an item in dropdown list. + */ + public function setDataValueField($value) + { + $this->setViewState('DataValueField',$value,''); + } + + /** + * @return boolean whether the items in the column can be edited. Defaults to false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return Traversable data source to be bound to the dropdown list boxes. + */ + public function getListDataSource() + { + return $this->_listControl->getDataSource(); + } + + /** + * @param Traversable|array|string data source to be bound to the dropdown list boxes. + */ + public function setListDataSource($value) + { + $this->_listControl->setDataSource($value); + } + + /** + * @return string the data field used to populate the values of the dropdown list items. Defaults to empty. + */ + public function getListValueField() + { + return $this->getViewState('ListValueField',''); + } + + /** + * @param string the data field used to populate the values of the dropdown list items + */ + public function setListValueField($value) + { + $this->setViewState('ListValueField',$value,''); + } + + /** + * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty. + */ + public function getListTextField() + { + return $this->getViewState('ListTextField',''); + } + + /** + * @param string the data field used to populate the texts of the dropdown list items + */ + public function setListTextField($value) + { + $this->setViewState('ListTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the list item texts will be displayed. + */ + public function getListTextFormatString() + { + return $this->getViewState('ListTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the list item texts will be displayed. + */ + public function setListTextFormatString($value) + { + $this->setViewState('ListTextFormatString',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a textbox for item in edit mode and the column is not read-only. + * Otherwise it displays a static text. + * The caption of the button and the static text are retrieved + * from the datasource. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if(!$this->_dataBound && $this->_listControl->getDataSource()!==null) + { + $this->_listControl->setDataTextField($this->getListTextField()); + $this->_listControl->setDataValueField($this->getListValueField()); + $this->_listControl->setDataTextFormatString($this->getListTextFormatString()); + $this->_listControl->dataBind(); + $this->_dataBound=true; + } + switch($itemType) + { + case TListItemType::EditItem: + if(!$this->getReadOnly()) + { + $listControl=clone $this->_listControl; + $cell->getControls()->add($listControl); + $cell->registerObject('DropDownList',$listControl); + $control=$listControl; + } + else + $control=$cell; + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + case TListItemType::Item: + case TListItemType::AlternatingItem: + case TListItemType::SelectedItem: + if($this->getDataTextField()!=='' || $this->getDataValueField()!=='') + $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + break; + default: + parent::initializeCell($cell,$columnIndex,$itemType); + break; + } + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + if(($valueField=$this->getDataValueField())!=='') + $value=$this->getDataFieldValue($data,$valueField); + else + $value=''; + if(($textField=$this->getDataTextField())!=='') + { + $text=$this->getDataFieldValue($data,$textField); + if($valueField==='') + $value=$text; + $formatString=$this->getDataTextFormatString(); + $text=$this->formatDataValue($formatString,$text); + } + else + $text=$value; + if($sender instanceof TTableCell) + $sender->setText($text); + else if($sender instanceof TDropDownList) + $sender->setSelectedValue($value); + } +} + diff --git a/framework/Web/UI/WebControls/TEditCommandColumn.php b/framework/Web/UI/WebControls/TEditCommandColumn.php index 44004807..b10c6880 100644 --- a/framework/Web/UI/WebControls/TEditCommandColumn.php +++ b/framework/Web/UI/WebControls/TEditCommandColumn.php @@ -1,265 +1,265 @@ -<?php
-/**
- * TEditCommandColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TEditCommandColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TEditCommandColumn class
- *
- * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
- *
- * TEditCommandColumn will create an edit button if a cell is not in edit mode.
- * Otherwise an update button and a cancel button will be created within the cell.
- * The button captions are specified using {@link setEditText EditText},
- * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
- *
- * The buttons in the column can be set to display as hyperlinks, push or image buttons
- * by setting the {@link setButtonType ButtonType} property.
- *
- * When an edit button is clicked, the datagrid will generate an
- * {@link onEditCommand OnEditCommand} event. When an update/cancel button
- * is clicked, the datagrid will generate an
- * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
- * You can write these event handlers to change the state of specific datagrid item.
- *
- * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
- * properties affect the corresponding properties of the edit and update buttons.
- * The cancel button does not cause validation by default.
- *
- * The command buttons in the column can be accessed by one of the following methods:
- * <code>
- * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
- * $datagridItem->ButtonColumnID->Controls[0]
- * </code>
- * The second method is possible because the button control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEditCommandColumn extends TDataGridColumn
-{
- /**
- * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
- }
-
- /**
- * @param TButtonColumnType the type of command button.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
- }
-
- /**
- * @return string the caption of the edit button. Defaults to 'Edit'.
- */
- public function getEditText()
- {
- return $this->getViewState('EditText','Edit');
- }
-
- /**
- * @param string the caption of the edit button
- */
- public function setEditText($value)
- {
- $this->setViewState('EditText',$value,'Edit');
- }
-
- /**
- * @return string the URL of the image file for edit image buttons
- */
- public function getEditImageUrl()
- {
- return $this->getViewState('EditImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for edit image buttons
- */
- public function setEditImageUrl($value)
- {
- $this->setViewState('EditImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the update button. Defaults to 'Update'.
- */
- public function getUpdateText()
- {
- return $this->getViewState('UpdateText','Update');
- }
-
- /**
- * @param string the caption of the update button
- */
- public function setUpdateText($value)
- {
- $this->setViewState('UpdateText',$value,'Update');
- }
-
- /**
- * @return string the URL of the image file for update image buttons
- */
- public function getUpdateImageUrl()
- {
- return $this->getViewState('UpdateImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for update image buttons
- */
- public function setUpdateImageUrl($value)
- {
- $this->setViewState('UpdateImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the cancel button. Defaults to 'Cancel'.
- */
- public function getCancelText()
- {
- return $this->getViewState('CancelText','Cancel');
- }
-
- /**
- * @param string the caption of the cancel button
- */
- public function setCancelText($value)
- {
- $this->setViewState('CancelText',$value,'Cancel');
- }
-
- /**
- * @return string the URL of the image file for cancel image buttons
- */
- public function getCancelImageUrl()
- {
- return $this->getViewState('CancelImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for cancel image buttons
- */
- public function setCancelImageUrl($value)
- {
- $this->setViewState('CancelImageUrl',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by edit or update button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the edit or update button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the edit or update button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates an update and a cancel button for cell in edit mode.
- * Otherwise it creates an edit button.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- $button=$this->createButton('Edit',$this->getEditText(),false,'');
- $cell->getControls()->add($button);
- $cell->registerObject('EditButton',$button);
- }
- else if($itemType===TListItemType::EditItem)
- {
- $controls=$cell->getControls();
- $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
- $controls->add($button);
- $cell->registerObject('UpdateButton',$button);
- $controls->add(' ');
- $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
- $controls->add($button);
- $cell->registerObject('CancelButton',$button);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Creates a button and initializes its properties.
- * The button type is determined by {@link getButtonType ButtonType}.
- * @param string command name associated with the button
- * @param string button caption
- * @param boolean whether the button should cause validation
- * @param string the validation group that the button belongs to
- * @return mixed the newly created button.
- */
- protected function createButton($commandName,$text,$causesValidation,$validationGroup)
- {
- if($this->getButtonType()===TButtonColumnType::LinkButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- else if($this->getButtonType()===TButtonColumnType::PushButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
- else // image buttons
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- if(strcasecmp($commandName,'Update')===0)
- $url=$this->getUpdateImageUrl();
- else if(strcasecmp($commandName,'Cancel')===0)
- $url=$this->getCancelImageUrl();
- else
- $url=$this->getEditImageUrl();
- $button->setImageUrl($url);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCausesValidation($causesValidation);
- $button->setValidationGroup($validationGroup);
- return $button;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TEditCommandColumn class + * + * TEditCommandColumn contains the Edit command buttons for editing data items in each row. + * + * TEditCommandColumn will create an edit button if a cell is not in edit mode. + * Otherwise an update button and a cancel button will be created within the cell. + * The button captions are specified using {@link setEditText EditText}, + * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}. + * + * The buttons in the column can be set to display as hyperlinks, push or image buttons + * by setting the {@link setButtonType ButtonType} property. + * + * When an edit button is clicked, the datagrid will generate an + * {@link onEditCommand OnEditCommand} event. When an update/cancel button + * is clicked, the datagrid will generate an + * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand} + * You can write these event handlers to change the state of specific datagrid item. + * + * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup} + * properties affect the corresponding properties of the edit and update buttons. + * The cancel button does not cause validation by default. + * + * The command buttons in the column can be accessed by one of the following methods: + * <code> + * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton) + * $datagridItem->ButtonColumnID->Controls[0] + * </code> + * The second method is possible because the button control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TEditCommandColumn extends TDataGridColumn +{ + /** + * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton. + */ + public function getButtonType() + { + return $this->getViewState('ButtonType',TButtonColumnType::LinkButton); + } + + /** + * @param TButtonColumnType the type of command button. + */ + public function setButtonType($value) + { + $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton); + } + + /** + * @return string the caption of the edit button. Defaults to 'Edit'. + */ + public function getEditText() + { + return $this->getViewState('EditText','Edit'); + } + + /** + * @param string the caption of the edit button + */ + public function setEditText($value) + { + $this->setViewState('EditText',$value,'Edit'); + } + + /** + * @return string the URL of the image file for edit image buttons + */ + public function getEditImageUrl() + { + return $this->getViewState('EditImageUrl',''); + } + + /** + * @param string the URL of the image file for edit image buttons + */ + public function setEditImageUrl($value) + { + $this->setViewState('EditImageUrl',$value,''); + } + + /** + * @return string the caption of the update button. Defaults to 'Update'. + */ + public function getUpdateText() + { + return $this->getViewState('UpdateText','Update'); + } + + /** + * @param string the caption of the update button + */ + public function setUpdateText($value) + { + $this->setViewState('UpdateText',$value,'Update'); + } + + /** + * @return string the URL of the image file for update image buttons + */ + public function getUpdateImageUrl() + { + return $this->getViewState('UpdateImageUrl',''); + } + + /** + * @param string the URL of the image file for update image buttons + */ + public function setUpdateImageUrl($value) + { + $this->setViewState('UpdateImageUrl',$value,''); + } + + /** + * @return string the caption of the cancel button. Defaults to 'Cancel'. + */ + public function getCancelText() + { + return $this->getViewState('CancelText','Cancel'); + } + + /** + * @param string the caption of the cancel button + */ + public function setCancelText($value) + { + $this->setViewState('CancelText',$value,'Cancel'); + } + + /** + * @return string the URL of the image file for cancel image buttons + */ + public function getCancelImageUrl() + { + return $this->getViewState('CancelImageUrl',''); + } + + /** + * @param string the URL of the image file for cancel image buttons + */ + public function setCancelImageUrl($value) + { + $this->setViewState('CancelImageUrl',$value,''); + } + + /** + * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by edit or update button will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the edit or update button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the edit or update button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates an update and a cancel button for cell in edit mode. + * Otherwise it creates an edit button. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem) + { + $button=$this->createButton('Edit',$this->getEditText(),false,''); + $cell->getControls()->add($button); + $cell->registerObject('EditButton',$button); + } + else if($itemType===TListItemType::EditItem) + { + $controls=$cell->getControls(); + $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup()); + $controls->add($button); + $cell->registerObject('UpdateButton',$button); + $controls->add(' '); + $button=$this->createButton('Cancel',$this->getCancelText(),false,''); + $controls->add($button); + $cell->registerObject('CancelButton',$button); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Creates a button and initializes its properties. + * The button type is determined by {@link getButtonType ButtonType}. + * @param string command name associated with the button + * @param string button caption + * @param boolean whether the button should cause validation + * @param string the validation group that the button belongs to + * @return mixed the newly created button. + */ + protected function createButton($commandName,$text,$causesValidation,$validationGroup) + { + if($this->getButtonType()===TButtonColumnType::LinkButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton'); + else if($this->getButtonType()===TButtonColumnType::PushButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TButton'); + else // image buttons + { + $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton'); + if(strcasecmp($commandName,'Update')===0) + $url=$this->getUpdateImageUrl(); + else if(strcasecmp($commandName,'Cancel')===0) + $url=$this->getCancelImageUrl(); + else + $url=$this->getEditImageUrl(); + $button->setImageUrl($url); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCausesValidation($causesValidation); + $button->setValidationGroup($validationGroup); + return $button; + } +} + diff --git a/framework/Web/UI/WebControls/TEmailAddressValidator.php b/framework/Web/UI/WebControls/TEmailAddressValidator.php index a198ffc4..b0b51208 100644 --- a/framework/Web/UI/WebControls/TEmailAddressValidator.php +++ b/framework/Web/UI/WebControls/TEmailAddressValidator.php @@ -1,97 +1,97 @@ -<?php
-/**
- * TEmailAddressValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TEmailAddressValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TRegularExpressionValidator class
- */
-Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
-
-/**
- * TEmailAddressValidator class
- *
- * TEmailAddressValidator validates whether the value of an associated
- * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
- * is true, it will check MX record for the email adress, provided
- * checkdnsrr() is available in the installed PHP.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEmailAddressValidator extends TRegularExpressionValidator
-{
- /**
- * Regular expression used to validate the email address
- */
- const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
-
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEmailAddressValidator';
- }
-
- /**
- * @return string the regular expression that determines the pattern used to validate a field.
- */
- public function getRegularExpression()
- {
- $regex=parent::getRegularExpression();
- return $regex===''?self::EMAIL_REGEXP:$regex;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- public function evaluateIsValid()
- {
- $valid=parent::evaluateIsValid();
- if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))!=='')
- {
- if(($pos=strpos($value,'@'))!==false)
- {
- $domain=substr($value,$pos+1);
- return $domain===''?false:checkdnsrr($domain,'MX');
- }
- else
- return false;
- }
- }
- return $valid;
- }
-
- /**
- * @return boolean whether to check MX record for the email address being validated. Defaults to true.
- */
- public function getCheckMXRecord()
- {
- return $this->getViewState('CheckMXRecord',true);
- }
-
- /**
- * @param boolean whether to check MX record for the email address being validated.
- * Note, if {@link checkdnsrr} is not available, this check will not be performed.
- */
- public function setCheckMXRecord($value)
- {
- $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TRegularExpressionValidator class + */ +Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator'); + +/** + * TEmailAddressValidator class + * + * TEmailAddressValidator validates whether the value of an associated + * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord} + * is true, it will check MX record for the email adress, provided + * checkdnsrr() is available in the installed PHP. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TEmailAddressValidator extends TRegularExpressionValidator +{ + /** + * Regular expression used to validate the email address + */ + const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; + + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TEmailAddressValidator'; + } + + /** + * @return string the regular expression that determines the pattern used to validate a field. + */ + public function getRegularExpression() + { + $regex=parent::getRegularExpression(); + return $regex===''?self::EMAIL_REGEXP:$regex; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + public function evaluateIsValid() + { + $valid=parent::evaluateIsValid(); + if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr')) + { + if(($value=$this->getValidationValue($this->getValidationTarget()))!=='') + { + if(($pos=strpos($value,'@'))!==false) + { + $domain=substr($value,$pos+1); + return $domain===''?false:checkdnsrr($domain,'MX'); + } + else + return false; + } + } + return $valid; + } + + /** + * @return boolean whether to check MX record for the email address being validated. Defaults to true. + */ + public function getCheckMXRecord() + { + return $this->getViewState('CheckMXRecord',true); + } + + /** + * @param boolean whether to check MX record for the email address being validated. + * Note, if {@link checkdnsrr} is not available, this check will not be performed. + */ + public function setCheckMXRecord($value) + { + $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true); + } +} + diff --git a/framework/Web/UI/WebControls/TExpression.php b/framework/Web/UI/WebControls/TExpression.php index 9b8eb7e7..cf38df70 100644 --- a/framework/Web/UI/WebControls/TExpression.php +++ b/framework/Web/UI/WebControls/TExpression.php @@ -1,62 +1,62 @@ -<?php
-/**
- * TExpression class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TExpression class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TExpression class
- *
- * TExpression evaluates a PHP expression and renders the result.
- * The expression is evaluated during the rendering stage. The expression being
- * evaluated can be set via the property {@link setExpression Expression}.
- * The context of the expression evaluated is the TExpression object itself.
- *
- * Note, since TExpression allows evaluation of arbitrary PHP expression,
- * make sure {@link setExpression Expression} does not come directly from user input.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TExpression extends TControl
-{
- /**
- * @var string PHP expression to be evaluated
- */
- private $_e='';
-
- /**
- * @return string the expression to be evaluated
- */
- public function getExpression()
- {
- return $this->_e;
- }
-
- /**
- * @param string the expression to be evaluated
- */
- public function setExpression($value)
- {
- $this->_e=$value;
- }
-
- /**
- * Renders the evaluation result of the expression.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_e!=='')
- $writer->write($this->evaluateExpression($this->_e));
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TExpression class + * + * TExpression evaluates a PHP expression and renders the result. + * The expression is evaluated during the rendering stage. The expression being + * evaluated can be set via the property {@link setExpression Expression}. + * The context of the expression evaluated is the TExpression object itself. + * + * Note, since TExpression allows evaluation of arbitrary PHP expression, + * make sure {@link setExpression Expression} does not come directly from user input. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TExpression extends TControl +{ + /** + * @var string PHP expression to be evaluated + */ + private $_e=''; + + /** + * @return string the expression to be evaluated + */ + public function getExpression() + { + return $this->_e; + } + + /** + * @param string the expression to be evaluated + */ + public function setExpression($value) + { + $this->_e=$value; + } + + /** + * Renders the evaluation result of the expression. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if($this->_e!=='') + $writer->write($this->evaluateExpression($this->_e)); + } +} + diff --git a/framework/Web/UI/WebControls/TFileUpload.php b/framework/Web/UI/WebControls/TFileUpload.php index 0f7d226d..051e3e0b 100644 --- a/framework/Web/UI/WebControls/TFileUpload.php +++ b/framework/Web/UI/WebControls/TFileUpload.php @@ -1,281 +1,281 @@ -<?php
-/**
- * TFileUpload class file
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFileUpload class
- *
- * TFileUpload displays a file upload field on a page. Upon postback,
- * the text entered into the field will be treated as the name of the file
- * that will be uploaded to the server. The property {@link getHasFile HasFile}
- * indicates whether the file upload is successful. If successful, the file
- * may be obtained by calling {@link saveAs} to save it at a specified place.
- * You can use {@link getFileName FileName}, {@link getFileType FileType},
- * {@link getFileSize FileSize} to get the original client-side file name,
- * the file mime type, and the file size information. If the upload is not
- * successful, {@link getErrorCode ErrorCode} contains the error code
- * describing the cause of failure.
- *
- * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
- * (whether it succeeds or not).
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
-{
- /**
- * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
- */
- const MAX_FILE_SIZE=1048576;
- /**
- * @var integer the size of the uploaded file (in bytes)
- */
- private $_fileSize=0;
- /**
- * @var string The original name of the file on the client machine
- */
- private $_fileName='';
- /**
- * @var string the name of the temporary file storing the uploaded file
- */
- private $_localName='';
- /**
- * @var string the uploaded file mime type
- */
- private $_fileType='';
- /**
- * @var integer error code of the current file upload
- */
- protected $_errorCode=UPLOAD_ERR_NO_FILE;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * @return string tag name of the file upload control
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets name attribute to the unique ID of the control.
- * This method overrides the parent implementation with additional file update control specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $this->getPage()->ensureRenderInForm($this);
- parent::addAttributesToRender($writer);
- $writer->addAttribute('type','file');
- $writer->addAttribute('name',$this->getUniqueID());
- $isEnabled=$this->getEnabled(true);
- if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Sets Enctype of the form on the page.
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if(($form=$this->getPage()->getForm())!==null)
- $form->setEnctype('multipart/form-data');
- $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
- * @see setMaxFileSize
- */
- public function getMaxFileSize()
- {
- return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
- }
-
- /**
- * Sets the maximum size that a file can be uploaded.
- * Note, this is an advisory value to the browser. Sets this property with
- * a reasonably large size to save users the trouble of waiting
- * for a big file being transferred only to find that it was too big
- * and the transfer failed.
- * @param int the maximum upload size allowed for a file.
- */
- public function setMaxFileSize($size)
- {
- $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
- }
-
- /**
- * @return string the original full path name of the file on the client machine
- */
- public function getFileName()
- {
- return $this->_fileName;
- }
-
- /**
- * @return integer the actual size of the uploaded file in bytes
- */
- public function getFileSize()
- {
- return $this->_fileSize;
- }
-
- /**
- * @return string the MIME-type of the uploaded file (such as "image/gif").
- * This mime type is not checked on the server side and do not take its value for granted.
- */
- public function getFileType()
- {
- return $this->_fileType;
- }
-
- /**
- * @return string the local name of the file (where it is after being uploaded).
- * Note, PHP will delete this file automatically after finishing this round of request.
- */
- public function getLocalName()
- {
- return $this->_localName;
- }
-
- /**
- * Returns an error code describing the status of this file uploading.
- * @return integer the error code
- * @see http://www.php.net/manual/en/features.file-upload.errors.php
- */
- public function getErrorCode()
- {
- return $this->_errorCode;
- }
-
- /**
- * @return boolean whether the file is uploaded successfully
- */
- public function getHasFile()
- {
- return $this->_errorCode===UPLOAD_ERR_OK;
- }
-
- /**
- * Saves the uploaded file.
- * @param string the file name used to save the uploaded file
- * @param boolean whether to delete the temporary file after saving.
- * If true, you will not be able to save the uploaded file again.
- * @return boolean true if the file saving is successful
- */
- public function saveAs($fileName,$deleteTempFile=true)
- {
- if($this->_errorCode===UPLOAD_ERR_OK)
- {
- if($deleteTempFile)
- return move_uploaded_file($this->_localName,$fileName);
- else if(is_uploaded_file($this->_localName))
- return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
- else
- return false;
- }
- else
- return false;
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if(isset($_FILES[$key]))
- {
- $this->_fileName=$_FILES[$key]['name'];
- $this->_fileSize=$_FILES[$key]['size'];
- $this->_fileType=$_FILES[$key]['type'];
- $this->_errorCode=$_FILES[$key]['error'];
- $this->_localName=$_FILES[$key]['tmp_name'];
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method calls {@link onFileUpload} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onFileUpload(null);
- }
-
- /**
- * This method is invoked when a file is uploaded during a postback.
- * The method raises <b>OnFileUpload</b> event to fire up the event handler.
- * If you override this method, be sure to call the parent implementation
- * so that the event delegates can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onFileUpload($param)
- {
- $this->raiseEvent('OnFileUpload',$this,$param);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the original file name as the property value to be validated.
- * This method is required by IValidatable property.
- * @return mixed the property value to be validated
- */
- public function getValidationPropertyValue()
- {
- return $this->getFileName();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
-}
-
+<?php +/** + * TFileUpload class file + * + * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TFileUpload class + * + * TFileUpload displays a file upload field on a page. Upon postback, + * the text entered into the field will be treated as the name of the file + * that will be uploaded to the server. The property {@link getHasFile HasFile} + * indicates whether the file upload is successful. If successful, the file + * may be obtained by calling {@link saveAs} to save it at a specified place. + * You can use {@link getFileName FileName}, {@link getFileType FileType}, + * {@link getFileSize FileSize} to get the original client-side file name, + * the file mime type, and the file size information. If the upload is not + * successful, {@link getErrorCode ErrorCode} contains the error code + * describing the cause of failure. + * + * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded + * (whether it succeeds or not). + * + * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable +{ + /** + * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB. + */ + const MAX_FILE_SIZE=1048576; + /** + * @var integer the size of the uploaded file (in bytes) + */ + private $_fileSize=0; + /** + * @var string The original name of the file on the client machine + */ + private $_fileName=''; + /** + * @var string the name of the temporary file storing the uploaded file + */ + private $_localName=''; + /** + * @var string the uploaded file mime type + */ + private $_fileType=''; + /** + * @var integer error code of the current file upload + */ + protected $_errorCode=UPLOAD_ERR_NO_FILE; + private $_dataChanged=false; + private $_isValid=true; + + /** + * @return string tag name of the file upload control + */ + protected function getTagName() + { + return 'input'; + } + + /** + * Sets name attribute to the unique ID of the control. + * This method overrides the parent implementation with additional file update control specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $this->getPage()->ensureRenderInForm($this); + parent::addAttributesToRender($writer); + $writer->addAttribute('type','file'); + $writer->addAttribute('name',$this->getUniqueID()); + $isEnabled=$this->getEnabled(true); + if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + } + + /** + * Sets Enctype of the form on the page. + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if(($form=$this->getPage()->getForm())!==null) + $form->setEnctype('multipart/form-data'); + $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize()); + if($this->getEnabled(true)) + $this->getPage()->registerRequiresPostData($this); + } + + /** + * @return integer the maximum file size, defaults to 1MB (1048576 bytes). + * @see setMaxFileSize + */ + public function getMaxFileSize() + { + return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE); + } + + /** + * Sets the maximum size that a file can be uploaded. + * Note, this is an advisory value to the browser. Sets this property with + * a reasonably large size to save users the trouble of waiting + * for a big file being transferred only to find that it was too big + * and the transfer failed. + * @param int the maximum upload size allowed for a file. + */ + public function setMaxFileSize($size) + { + $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE); + } + + /** + * @return string the original full path name of the file on the client machine + */ + public function getFileName() + { + return $this->_fileName; + } + + /** + * @return integer the actual size of the uploaded file in bytes + */ + public function getFileSize() + { + return $this->_fileSize; + } + + /** + * @return string the MIME-type of the uploaded file (such as "image/gif"). + * This mime type is not checked on the server side and do not take its value for granted. + */ + public function getFileType() + { + return $this->_fileType; + } + + /** + * @return string the local name of the file (where it is after being uploaded). + * Note, PHP will delete this file automatically after finishing this round of request. + */ + public function getLocalName() + { + return $this->_localName; + } + + /** + * Returns an error code describing the status of this file uploading. + * @return integer the error code + * @see http://www.php.net/manual/en/features.file-upload.errors.php + */ + public function getErrorCode() + { + return $this->_errorCode; + } + + /** + * @return boolean whether the file is uploaded successfully + */ + public function getHasFile() + { + return $this->_errorCode===UPLOAD_ERR_OK; + } + + /** + * Saves the uploaded file. + * @param string the file name used to save the uploaded file + * @param boolean whether to delete the temporary file after saving. + * If true, you will not be able to save the uploaded file again. + * @return boolean true if the file saving is successful + */ + public function saveAs($fileName,$deleteTempFile=true) + { + if($this->_errorCode===UPLOAD_ERR_OK) + { + if($deleteTempFile) + return move_uploaded_file($this->_localName,$fileName); + else if(is_uploaded_file($this->_localName)) + return file_put_contents($fileName,file_get_contents($this->_localName))!==false; + else + return false; + } + else + return false; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + if(isset($_FILES[$key])) + { + $this->_fileName=$_FILES[$key]['name']; + $this->_fileSize=$_FILES[$key]['size']; + $this->_fileType=$_FILES[$key]['type']; + $this->_errorCode=$_FILES[$key]['error']; + $this->_localName=$_FILES[$key]['tmp_name']; + return $this->_dataChanged=true; + } + else + return false; + } + + /** + * Raises postdata changed event. + * This method calls {@link onFileUpload} method. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onFileUpload(null); + } + + /** + * This method is invoked when a file is uploaded during a postback. + * The method raises <b>OnFileUpload</b> event to fire up the event handler. + * If you override this method, be sure to call the parent implementation + * so that the event delegates can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onFileUpload($param) + { + $this->raiseEvent('OnFileUpload',$this,$param); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the original file name as the property value to be validated. + * This method is required by IValidatable property. + * @return mixed the property value to be validated + */ + public function getValidationPropertyValue() + { + return $this->getFileName(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + +} + diff --git a/framework/Web/UI/WebControls/TFlushOutput.php b/framework/Web/UI/WebControls/TFlushOutput.php index cc55646d..0ea9b389 100644 --- a/framework/Web/UI/WebControls/TFlushOutput.php +++ b/framework/Web/UI/WebControls/TFlushOutput.php @@ -1,86 +1,86 @@ -<?php
-/**
- * TFlushOutput class file
- *
- * @author Berczi Gabor <gabor.berczi@devworx.hu>
- * @link http://www.pradosoft.com/
- * @license http://www.pradosoft.com/license/
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFlushOutput class.
- *
- * TFlushOutput enables forced flushing of the current output buffer
- * at (a) certain point(s) in the page, after rendering of all previous
- * controls has been completed.
- *
- * To use TFlushOutput, simply place it in a template where you want
- * the have the output buffered between the start of the page or the
- * last TFlushOutput to be sent to the client immediately
- * <code>
- * <com:TFlushOutput />
- * </code>
- *
- * You can specify whether you want to keep buffering of the output
- * (if it was enabled) till the next occourence of a <com: TFlushOutput />
- * or the end of the page rendering, or stop buffering, by using the
- * {@link setContinueBuffering ContinueBuffering}.
- *
- * @author Berczi Gabor <gabor.berczi@devworx.hu>
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TFlushOutput extends TControl
-{
- /**
- * @var boolean whether to continue buffering of output
- */
- private $_continueBuffering=true;
-
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->EnableViewState = false;
- }
-
- /**
- * @return Tells whether buffering of output can continue after this point
- */
- public function getContinueBuffering()
- {
- return $this->_continueBuffering;
- }
-
- /**
- * @param boolean sets whether buffering of output can continue after this point
- */
- public function setContinueBuffering($value)
- {
- $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Flushes the output of all completely rendered controls to the client.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
-//$writer->write('<!-- flush -->');
- // ajax responses can't be parsed by the client side before loaded and returned completely,
- // so don't bother with flushing output somewhere mid-page if refreshing in a callback
- if (!$this->Page->IsCallback)
- {
- $this->Page->flushWriter();
-// $this->Application->flushOutput($this->ContinueBuffering);
- }
- }
-}
-
+<?php +/** + * TFlushOutput class file + * + * @author Berczi Gabor <gabor.berczi@devworx.hu> + * @link http://www.pradosoft.com/ + * @license http://www.pradosoft.com/license/ + * @version $Id: TFlushOutput.php $ + * @package System.Web.UI.WebControls + */ + +/** + * TFlushOutput class. + * + * TFlushOutput enables forced flushing of the current output buffer + * at (a) certain point(s) in the page, after rendering of all previous + * controls has been completed. + * + * To use TFlushOutput, simply place it in a template where you want + * the have the output buffered between the start of the page or the + * last TFlushOutput to be sent to the client immediately + * <code> + * <com:TFlushOutput /> + * </code> + * + * You can specify whether you want to keep buffering of the output + * (if it was enabled) till the next occourence of a <com: TFlushOutput /> + * or the end of the page rendering, or stop buffering, by using the + * {@link setContinueBuffering ContinueBuffering}. + * + * @author Berczi Gabor <gabor.berczi@devworx.hu> + * @version $Id: TFlushOutput.php $ + * @package System.Web.UI.WebControls + * @since 3.1 + */ +class TFlushOutput extends TControl +{ + /** + * @var boolean whether to continue buffering of output + */ + private $_continueBuffering=true; + + + /** + * Constructor. + */ + public function __construct() + { + parent::__construct(); + $this->EnableViewState = false; + } + + /** + * @return Tells whether buffering of output can continue after this point + */ + public function getContinueBuffering() + { + return $this->_continueBuffering; + } + + /** + * @param boolean sets whether buffering of output can continue after this point + */ + public function setContinueBuffering($value) + { + $this->_continueBuffering = TPropertyValue::ensureBoolean($value); + } + + /** + * Flushes the output of all completely rendered controls to the client. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { +//$writer->write('<!-- flush -->'); + // ajax responses can't be parsed by the client side before loaded and returned completely, + // so don't bother with flushing output somewhere mid-page if refreshing in a callback + if (!$this->Page->IsCallback) + { + $this->Page->flushWriter(); +// $this->Application->flushOutput($this->ContinueBuffering); + } + } +} + ?>
\ No newline at end of file diff --git a/framework/Web/UI/WebControls/TFont.php b/framework/Web/UI/WebControls/TFont.php index 4da42508..771b6a4e 100644 --- a/framework/Web/UI/WebControls/TFont.php +++ b/framework/Web/UI/WebControls/TFont.php @@ -1,318 +1,318 @@ -<?php
-/**
- * TFont class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TFont class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFont class
- *
- * TFont encapsulates the CSS style fields related with font settings.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFont extends TComponent
-{
- /**
- * Bits indicating the font states.
- */
- const IS_BOLD=0x01;
- const IS_ITALIC=0x02;
- const IS_OVERLINE=0x04;
- const IS_STRIKEOUT=0x08;
- const IS_UNDERLINE=0x10;
-
- /**
- * Bits indicating whether particular font states are changed.
- */
- const IS_SET_BOLD=0x01000;
- const IS_SET_ITALIC=0x02000;
- const IS_SET_OVERLINE=0x04000;
- const IS_SET_STRIKEOUT=0x08000;
- const IS_SET_UNDERLINE=0x10000;
- const IS_SET_SIZE=0x20000;
- const IS_SET_NAME=0x40000;
-
- /**
- * @var integer bits representing various states
- */
- private $_flags=0;
- /**
- * @var string font name
- */
- private $_name='';
- /**
- * @var string font size
- */
- private $_size='';
-
- /**
- * @return boolean whether the font is in bold face. Defaults to false.
- */
- public function getBold()
- {
- return ($this->_flags & self::IS_BOLD)!==0;
- }
-
- /**
- * @param boolean whether the font is in bold face
- */
- public function setBold($value)
- {
- $this->_flags |= self::IS_SET_BOLD;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_BOLD;
- else
- $this->_flags &= ~self::IS_BOLD;
- }
-
- /**
- * @return boolean whether the font is in italic face. Defaults to false.
- */
- public function getItalic()
- {
- return ($this->_flags & self::IS_ITALIC)!==0;
- }
-
- /**
- * @param boolean whether the font is italic
- */
- public function setItalic($value)
- {
- $this->_flags |= self::IS_SET_ITALIC;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_ITALIC;
- else
- $this->_flags &= ~self::IS_ITALIC;
- }
-
- /**
- * @return boolean whether the font is overlined. Defaults to false.
- */
- public function getOverline()
- {
- return ($this->_flags & self::IS_OVERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is overlined
- */
- public function setOverline($value)
- {
- $this->_flags |= self::IS_SET_OVERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_OVERLINE;
- else
- $this->_flags &= ~self::IS_OVERLINE;
- }
-
- /**
- * @return string the font size
- */
- public function getSize()
- {
- return $this->_size;
- }
-
- /**
- * @param string the font size
- */
- public function setSize($value)
- {
- $this->_flags |= self::IS_SET_SIZE;
- $this->_size=$value;
- }
-
- /**
- * @return boolean whether the font is strikeout. Defaults to false.
- */
- public function getStrikeout()
- {
- return ($this->_flags & self::IS_STRIKEOUT)!==0;
- }
-
- /**
- * @param boolean whether the font is strikeout
- */
- public function setStrikeout($value)
- {
- $this->_flags |= self::IS_SET_STRIKEOUT;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_STRIKEOUT;
- else
- $this->_flags &= ~self::IS_STRIKEOUT;
- }
-
- /**
- * @return boolean whether the font is underlined. Defaults to false.
- */
- public function getUnderline()
- {
- return ($this->_flags & self::IS_UNDERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is underlined
- */
- public function setUnderline($value)
- {
- $this->_flags |= self::IS_SET_UNDERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_UNDERLINE;
- else
- $this->_flags &= ~self::IS_UNDERLINE;
- }
-
- /**
- * @return string the font name (family)
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string the font name (family)
- */
- public function setName($value)
- {
- $this->_flags |= self::IS_SET_NAME;
- $this->_name=$value;
- }
-
- /**
- * @return boolean whether the font is empty
- */
- public function getIsEmpty()
- {
- return !$this->_flags;
- }
-
- /**
- * Clears up the font.
- */
- public function reset()
- {
- $this->_flags=0;
- $this->_name='';
- $this->_size='';
- }
-
- /**
- * Merges the font with a new one.
- * If a font field is not set in the font, it will be overwritten with
- * the new one.
- * @param TFont the new font
- */
- public function mergeWith($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
- $this->setBold($font->getBold());
- if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
- $this->setItalic($font->getItalic());
- if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
- $this->setOverline($font->getOverline());
- if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
- $this->setStrikeout($font->getStrikeout());
- if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
- $this->setUnderline($font->getUnderline());
- if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
- $this->setSize($font->getSize());
- if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
- $this->setName($font->getName());
- }
-
- /**
- * Copies the fields in a new font to this font.
- * If a font field is set in the new font, the corresponding field
- * in this font will be overwritten.
- * @param TFont the new font
- */
- public function copyFrom($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if($font->_flags & self::IS_SET_BOLD)
- $this->setBold($font->getBold());
- if($font->_flags & self::IS_SET_ITALIC)
- $this->setItalic($font->getItalic());
- if($font->_flags & self::IS_SET_OVERLINE)
- $this->setOverline($font->getOverline());
- if($font->_flags & self::IS_SET_STRIKEOUT)
- $this->setStrikeout($font->getStrikeout());
- if($font->_flags & self::IS_SET_UNDERLINE)
- $this->setUnderline($font->getUnderline());
- if($font->_flags & self::IS_SET_SIZE)
- $this->setSize($font->getSize());
- if($font->_flags & self::IS_SET_NAME)
- $this->setName($font->getName());
- }
-
- /**
- * @return string the font in a css style string representation.
- */
- public function toString()
- {
- if($this->_flags===0)
- return '';
- $str='';
- if($this->_flags & self::IS_SET_BOLD)
- $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
- if($this->_flags & self::IS_SET_ITALIC)
- $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $str.='text-decoration:'.$textDec.';';
- if($this->_size!=='')
- $str.='font-size:'.$this->_size.';';
- if($this->_name!=='')
- $str.='font-family:'.$this->_name.';';
- return $str;
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if($this->_flags===0)
- return;
- if($this->_flags & self::IS_SET_BOLD)
- $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
- if($this->_flags & self::IS_SET_ITALIC)
- $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $writer->addStyleAttribute('text-decoration',$textDec);
- if($this->_size!=='')
- $writer->addStyleAttribute('font-size',$this->_size);
- if($this->_name!=='')
- $writer->addStyleAttribute('font-family',$this->_name);
- }
-}
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TFont class + * + * TFont encapsulates the CSS style fields related with font settings. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TFont extends TComponent +{ + /** + * Bits indicating the font states. + */ + const IS_BOLD=0x01; + const IS_ITALIC=0x02; + const IS_OVERLINE=0x04; + const IS_STRIKEOUT=0x08; + const IS_UNDERLINE=0x10; + + /** + * Bits indicating whether particular font states are changed. + */ + const IS_SET_BOLD=0x01000; + const IS_SET_ITALIC=0x02000; + const IS_SET_OVERLINE=0x04000; + const IS_SET_STRIKEOUT=0x08000; + const IS_SET_UNDERLINE=0x10000; + const IS_SET_SIZE=0x20000; + const IS_SET_NAME=0x40000; + + /** + * @var integer bits representing various states + */ + private $_flags=0; + /** + * @var string font name + */ + private $_name=''; + /** + * @var string font size + */ + private $_size=''; + + /** + * @return boolean whether the font is in bold face. Defaults to false. + */ + public function getBold() + { + return ($this->_flags & self::IS_BOLD)!==0; + } + + /** + * @param boolean whether the font is in bold face + */ + public function setBold($value) + { + $this->_flags |= self::IS_SET_BOLD; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_BOLD; + else + $this->_flags &= ~self::IS_BOLD; + } + + /** + * @return boolean whether the font is in italic face. Defaults to false. + */ + public function getItalic() + { + return ($this->_flags & self::IS_ITALIC)!==0; + } + + /** + * @param boolean whether the font is italic + */ + public function setItalic($value) + { + $this->_flags |= self::IS_SET_ITALIC; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_ITALIC; + else + $this->_flags &= ~self::IS_ITALIC; + } + + /** + * @return boolean whether the font is overlined. Defaults to false. + */ + public function getOverline() + { + return ($this->_flags & self::IS_OVERLINE)!==0; + } + + /** + * @param boolean whether the font is overlined + */ + public function setOverline($value) + { + $this->_flags |= self::IS_SET_OVERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_OVERLINE; + else + $this->_flags &= ~self::IS_OVERLINE; + } + + /** + * @return string the font size + */ + public function getSize() + { + return $this->_size; + } + + /** + * @param string the font size + */ + public function setSize($value) + { + $this->_flags |= self::IS_SET_SIZE; + $this->_size=$value; + } + + /** + * @return boolean whether the font is strikeout. Defaults to false. + */ + public function getStrikeout() + { + return ($this->_flags & self::IS_STRIKEOUT)!==0; + } + + /** + * @param boolean whether the font is strikeout + */ + public function setStrikeout($value) + { + $this->_flags |= self::IS_SET_STRIKEOUT; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_STRIKEOUT; + else + $this->_flags &= ~self::IS_STRIKEOUT; + } + + /** + * @return boolean whether the font is underlined. Defaults to false. + */ + public function getUnderline() + { + return ($this->_flags & self::IS_UNDERLINE)!==0; + } + + /** + * @param boolean whether the font is underlined + */ + public function setUnderline($value) + { + $this->_flags |= self::IS_SET_UNDERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_UNDERLINE; + else + $this->_flags &= ~self::IS_UNDERLINE; + } + + /** + * @return string the font name (family) + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string the font name (family) + */ + public function setName($value) + { + $this->_flags |= self::IS_SET_NAME; + $this->_name=$value; + } + + /** + * @return boolean whether the font is empty + */ + public function getIsEmpty() + { + return !$this->_flags; + } + + /** + * Clears up the font. + */ + public function reset() + { + $this->_flags=0; + $this->_name=''; + $this->_size=''; + } + + /** + * Merges the font with a new one. + * If a font field is not set in the font, it will be overwritten with + * the new one. + * @param TFont the new font + */ + public function mergeWith($font) + { + if($font===null || $font->_flags===0) + return; + if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD)) + $this->setBold($font->getBold()); + if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC)) + $this->setItalic($font->getItalic()); + if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE)) + $this->setOverline($font->getOverline()); + if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT)) + $this->setStrikeout($font->getStrikeout()); + if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE)) + $this->setUnderline($font->getUnderline()); + if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE)) + $this->setSize($font->getSize()); + if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME)) + $this->setName($font->getName()); + } + + /** + * Copies the fields in a new font to this font. + * If a font field is set in the new font, the corresponding field + * in this font will be overwritten. + * @param TFont the new font + */ + public function copyFrom($font) + { + if($font===null || $font->_flags===0) + return; + if($font->_flags & self::IS_SET_BOLD) + $this->setBold($font->getBold()); + if($font->_flags & self::IS_SET_ITALIC) + $this->setItalic($font->getItalic()); + if($font->_flags & self::IS_SET_OVERLINE) + $this->setOverline($font->getOverline()); + if($font->_flags & self::IS_SET_STRIKEOUT) + $this->setStrikeout($font->getStrikeout()); + if($font->_flags & self::IS_SET_UNDERLINE) + $this->setUnderline($font->getUnderline()); + if($font->_flags & self::IS_SET_SIZE) + $this->setSize($font->getSize()); + if($font->_flags & self::IS_SET_NAME) + $this->setName($font->getName()); + } + + /** + * @return string the font in a css style string representation. + */ + public function toString() + { + if($this->_flags===0) + return ''; + $str=''; + if($this->_flags & self::IS_SET_BOLD) + $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;'); + if($this->_flags & self::IS_SET_ITALIC) + $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;'); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $str.='text-decoration:'.$textDec.';'; + if($this->_size!=='') + $str.='font-size:'.$this->_size.';'; + if($this->_name!=='') + $str.='font-family:'.$this->_name.';'; + return $str; + } + + /** + * Adds attributes related to CSS styles to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if($this->_flags===0) + return; + if($this->_flags & self::IS_SET_BOLD) + $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal')); + if($this->_flags & self::IS_SET_ITALIC) + $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal')); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $writer->addStyleAttribute('text-decoration',$textDec); + if($this->_size!=='') + $writer->addStyleAttribute('font-size',$this->_size); + if($this->_name!=='') + $writer->addStyleAttribute('font-family',$this->_name); + } +} diff --git a/framework/Web/UI/WebControls/THead.php b/framework/Web/UI/WebControls/THead.php index c0042c22..7966f2d3 100644 --- a/framework/Web/UI/WebControls/THead.php +++ b/framework/Web/UI/WebControls/THead.php @@ -1,377 +1,377 @@ -<?php
-/**
- * THead class file
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THead class
- *
- * THead displays a head element on a page. It displays the content
- * enclosed in its body and the page title set by the
- * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
- * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
- * {@link TClientScriptManager::registerHeadJavaScript}, and
- * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
- * in the head.
- * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
- * property. You can add a meta object to the collection in code dynamically,
- * or add it in template using the following syntax,
- * <code>
- * <com:THead>
- * <com:TMetaTag HttpEquiv="Pragma" Content="no-cache" />
- * <com:TMetaTag Name="keywords" Content="Prado" />
- * </com:THead>
- * </code>
- *
- * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
- * the THead control currently on the page. A page can have at most one THead
- * control. Although not required, it is recommended to place a THead on your page.
- * Without a THead on the page, stylesheets and javascripts in the current page
- * theme will not be rendered.
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THead extends TControl
-{
- /**
- * @var TList list of meta name tags to be loaded by {@link THead}
- */
- private $_metaTags=null;
-
- /**
- * Registers the head control with the current page.
- * This method is invoked when the control enters 'Init' stage.
- * The method raises 'Init' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setHead($this);
- }
-
- /**
- * Processes an object that is created during parsing template.
- * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
- * collection of the head control.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- if($object instanceof TMetaTag)
- $this->getMetaTags()->add($object);
- else
- parent::addParsedObject($object);
- }
-
- /**
- * @return string the page title.
- */
- public function getTitle()
- {
- return $this->getViewState('Title','');
- }
-
- /**
- * Sets the page title.
- * This title will be rendered only if the {@link TPage::getTitle Title} property
- * of the page is empty.
- * @param string the page title.
- */
- public function setTitle($value)
- {
- $this->setViewState('Title',$value,'');
- }
-
- /**
- * @return string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. Defaults to ''.
- */
- public function getBaseUrl()
- {
- return $this->getViewState('BaseUrl','');
- }
-
- /**
- * @param string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag.
- */
- public function setBaseUrl($url)
- {
- $this->setViewState('BaseUrl',$url,'');
- }
-
- /**
- * @return string the URL for the shortcut icon of the page. Defaults to ''.
- */
- public function getShortcutIcon()
- {
- return $this->getViewState('ShortcutIcon','');
- }
-
- /**
- * @param string the URL for the shortcut icon of the page.
- */
- public function setShortcutIcon($url)
- {
- $this->setViewState('ShortcutIcon',$url,'');
- }
-
- /**
- * @return TMetaTagCollection meta tag collection
- */
- public function getMetaTags()
- {
- if(($metaTags=$this->getViewState('MetaTags',null))===null)
- {
- $metaTags=new TMetaTagCollection;
- $this->setViewState('MetaTags',$metaTags,null);
- }
- return $metaTags;
- }
-
- /**
- * Renders the head control.
- * @param THtmlWriter the writer for rendering purpose.
- */
- public function render($writer)
- {
- $page=$this->getPage();
- $title=$this->getTitle();
- $writer->write("<head>\n<title>".THttpUtility::htmlEncode($title)."</title>\n");
- if(($baseUrl=$this->getBaseUrl())!=='')
- $writer->write('<base href="'.$baseUrl."\" />\n");
- if(($icon=$this->getShortcutIcon())!=='')
- $writer->write('<link rel="shortcut icon" href="'.$icon."\" />\n");
-
- if(($metaTags=$this->getMetaTags())!==null)
- {
- foreach($metaTags as $metaTag)
- {
- $metaTag->render($writer);
- $writer->writeLine();
- }
- }
- $cs=$page->getClientScript();
- $cs->renderStyleSheetFiles($writer);
- $cs->renderStyleSheets($writer);
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHeadScriptFiles($writer);
- $cs->renderHeadScripts($writer);
- }
- parent::render($writer);
- $writer->write("</head>\n");
- }
-}
-
-/**
- * TMetaTag class.
- *
- * TMetaTag represents a meta tag appearing in a page head section.
- * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
- * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
- * properties, which correspond to id, http-equiv, name, content, and scheme
- * attributes for a meta tag, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTag extends TComponent
-{
- /**
- * @var string id of the meta tag
- */
- private $_id='';
- /**
- * @var string http-equiv attribute of the meta tag
- */
- private $_httpEquiv='';
- /**
- * @var string name attribute of the meta tag
- */
- private $_name='';
- /**
- * @var string content attribute of the meta tag
- */
- private $_content='';
- /**
- * @var string scheme attribute of the meta tag
- */
- private $_scheme='';
-
- /**
- * @return string id of the meta tag
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * @param string id of the meta tag
- */
- public function setID($value)
- {
- $this->_id=$value;
- }
-
- /**
- * @return string http-equiv attribute of the meta tag
- */
- public function getHttpEquiv()
- {
- return $this->_httpEquiv;
- }
-
- /**
- * @param string http-equiv attribute of the meta tag
- */
- public function setHttpEquiv($value)
- {
- $this->_httpEquiv=$value;
- }
-
- /**
- * @return string name attribute of the meta tag
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string name attribute of the meta tag
- */
- public function setName($value)
- {
- $this->_name=$value;
- }
-
- /**
- * @return string content attribute of the meta tag
- */
- public function getContent()
- {
- return $this->_content;
- }
-
- /**
- * @param string content attribute of the meta tag
- */
- public function setContent($value)
- {
- $this->_content=$value;
- }
-
- /**
- * @return string scheme attribute of the meta tag
- */
- public function getScheme()
- {
- return $this->_scheme;
- }
-
- /**
- * @param string scheme attribute of the meta tag
- */
- public function setScheme($value)
- {
- $this->_scheme=$value;
- }
-
- /**
- * Renders the meta tag.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_id!=='')
- $writer->addAttribute('id',$this->_id);
- if($this->_name!=='')
- $writer->addAttribute('name',$this->_name);
- if($this->_httpEquiv!=='')
- $writer->addAttribute('http-equiv',$this->_httpEquiv);
- if($this->_scheme!=='')
- $writer->addAttribute('scheme',$this->_scheme);
- $writer->addAttribute('content',$this->_content);
- $writer->renderBeginTag('meta');
- $writer->renderEndTag();
- }
-}
-
-
-/**
- * TMetaTagCollection class
- *
- * TMetaTagCollection represents a collection of meta tags
- * contained in a {@link THead} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTagCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing type
- * check on the item being added.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TMetaTag)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
- }
-
- /**
- * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
- * @param string the ID of the meta tag to be looked for
- * @return integer the index of the meta tag found, -1 if not found.
- */
- public function findIndexByID($id)
- {
- $index=0;
- foreach($this as $item)
- {
- if($item->getID()===$id)
- return $index;
- $index++;
- }
- return -1;
- }
-
- /**
- * Finds the item whose value is the one being looked for.
- * @param string the id of the meta tag to be looked for
- * @return TMetaTag the meta tag found, null if not found.
- */
- public function findMetaTagByID($id)
- {
- if(($index=$this->findIndexByID($id))>=0)
- return $this->itemAt($index);
- else
- return null;
- }
-}
-
-?>
+<?php +/** + * THead class file + * + * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI + */ + +/** + * THead class + * + * THead displays a head element on a page. It displays the content + * enclosed in its body and the page title set by the + * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via + * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile} + * {@link TClientScriptManager::registerHeadJavaScript}, and + * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed + * in the head. + * THead also manages and displays meta tags through its {@link getMetaTags MetaTags} + * property. You can add a meta object to the collection in code dynamically, + * or add it in template using the following syntax, + * <code> + * <com:THead> + * <com:TMetaTag HttpEquiv="Pragma" Content="no-cache" /> + * <com:TMetaTag Name="keywords" Content="Prado" /> + * </com:THead> + * </code> + * + * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to + * the THead control currently on the page. A page can have at most one THead + * control. Although not required, it is recommended to place a THead on your page. + * Without a THead on the page, stylesheets and javascripts in the current page + * theme will not be rendered. + * + * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0 + */ +class THead extends TControl +{ + /** + * @var TList list of meta name tags to be loaded by {@link THead} + */ + private $_metaTags=null; + + /** + * Registers the head control with the current page. + * This method is invoked when the control enters 'Init' stage. + * The method raises 'Init' event. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onInit($param) + { + parent::onInit($param); + $this->getPage()->setHead($this); + } + + /** + * Processes an object that is created during parsing template. + * This method adds TMetaTag components into the {@link getMetaTags MetaTags} + * collection of the head control. + * @param string|TComponent text string or component parsed and instantiated in template + * @see createdOnTemplate + */ + public function addParsedObject($object) + { + if($object instanceof TMetaTag) + $this->getMetaTags()->add($object); + else + parent::addParsedObject($object); + } + + /** + * @return string the page title. + */ + public function getTitle() + { + return $this->getViewState('Title',''); + } + + /** + * Sets the page title. + * This title will be rendered only if the {@link TPage::getTitle Title} property + * of the page is empty. + * @param string the page title. + */ + public function setTitle($value) + { + $this->setViewState('Title',$value,''); + } + + /** + * @return string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. Defaults to ''. + */ + public function getBaseUrl() + { + return $this->getViewState('BaseUrl',''); + } + + /** + * @param string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. + */ + public function setBaseUrl($url) + { + $this->setViewState('BaseUrl',$url,''); + } + + /** + * @return string the URL for the shortcut icon of the page. Defaults to ''. + */ + public function getShortcutIcon() + { + return $this->getViewState('ShortcutIcon',''); + } + + /** + * @param string the URL for the shortcut icon of the page. + */ + public function setShortcutIcon($url) + { + $this->setViewState('ShortcutIcon',$url,''); + } + + /** + * @return TMetaTagCollection meta tag collection + */ + public function getMetaTags() + { + if(($metaTags=$this->getViewState('MetaTags',null))===null) + { + $metaTags=new TMetaTagCollection; + $this->setViewState('MetaTags',$metaTags,null); + } + return $metaTags; + } + + /** + * Renders the head control. + * @param THtmlWriter the writer for rendering purpose. + */ + public function render($writer) + { + $page=$this->getPage(); + $title=$this->getTitle(); + $writer->write("<head>\n<title>".THttpUtility::htmlEncode($title)."</title>\n"); + if(($baseUrl=$this->getBaseUrl())!=='') + $writer->write('<base href="'.$baseUrl."\" />\n"); + if(($icon=$this->getShortcutIcon())!=='') + $writer->write('<link rel="shortcut icon" href="'.$icon."\" />\n"); + + if(($metaTags=$this->getMetaTags())!==null) + { + foreach($metaTags as $metaTag) + { + $metaTag->render($writer); + $writer->writeLine(); + } + } + $cs=$page->getClientScript(); + $cs->renderStyleSheetFiles($writer); + $cs->renderStyleSheets($writer); + if($page->getClientSupportsJavaScript()) + { + $cs->renderHeadScriptFiles($writer); + $cs->renderHeadScripts($writer); + } + parent::render($writer); + $writer->write("</head>\n"); + } +} + +/** + * TMetaTag class. + * + * TMetaTag represents a meta tag appearing in a page head section. + * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv}, + * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme} + * properties, which correspond to id, http-equiv, name, content, and scheme + * attributes for a meta tag, respectively. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TMetaTag extends TComponent +{ + /** + * @var string id of the meta tag + */ + private $_id=''; + /** + * @var string http-equiv attribute of the meta tag + */ + private $_httpEquiv=''; + /** + * @var string name attribute of the meta tag + */ + private $_name=''; + /** + * @var string content attribute of the meta tag + */ + private $_content=''; + /** + * @var string scheme attribute of the meta tag + */ + private $_scheme=''; + + /** + * @return string id of the meta tag + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string id of the meta tag + */ + public function setID($value) + { + $this->_id=$value; + } + + /** + * @return string http-equiv attribute of the meta tag + */ + public function getHttpEquiv() + { + return $this->_httpEquiv; + } + + /** + * @param string http-equiv attribute of the meta tag + */ + public function setHttpEquiv($value) + { + $this->_httpEquiv=$value; + } + + /** + * @return string name attribute of the meta tag + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string name attribute of the meta tag + */ + public function setName($value) + { + $this->_name=$value; + } + + /** + * @return string content attribute of the meta tag + */ + public function getContent() + { + return $this->_content; + } + + /** + * @param string content attribute of the meta tag + */ + public function setContent($value) + { + $this->_content=$value; + } + + /** + * @return string scheme attribute of the meta tag + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @param string scheme attribute of the meta tag + */ + public function setScheme($value) + { + $this->_scheme=$value; + } + + /** + * Renders the meta tag. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->_id!=='') + $writer->addAttribute('id',$this->_id); + if($this->_name!=='') + $writer->addAttribute('name',$this->_name); + if($this->_httpEquiv!=='') + $writer->addAttribute('http-equiv',$this->_httpEquiv); + if($this->_scheme!=='') + $writer->addAttribute('scheme',$this->_scheme); + $writer->addAttribute('content',$this->_content); + $writer->renderBeginTag('meta'); + $writer->renderEndTag(); + } +} + + +/** + * TMetaTagCollection class + * + * TMetaTagCollection represents a collection of meta tags + * contained in a {@link THead} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TMetaTagCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing type + * check on the item being added. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag} + */ + public function insertAt($index,$item) + { + if($item instanceof TMetaTag) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('metatagcollection_metatag_invalid'); + } + + /** + * Finds the lowest cardinal index of the meta tag whose id is the one being looked for. + * @param string the ID of the meta tag to be looked for + * @return integer the index of the meta tag found, -1 if not found. + */ + public function findIndexByID($id) + { + $index=0; + foreach($this as $item) + { + if($item->getID()===$id) + return $index; + $index++; + } + return -1; + } + + /** + * Finds the item whose value is the one being looked for. + * @param string the id of the meta tag to be looked for + * @return TMetaTag the meta tag found, null if not found. + */ + public function findMetaTagByID($id) + { + if(($index=$this->findIndexByID($id))>=0) + return $this->itemAt($index); + else + return null; + } +} + +?> diff --git a/framework/Web/UI/WebControls/THiddenField.php b/framework/Web/UI/WebControls/THiddenField.php index ac8ddfff..ec330d54 100644 --- a/framework/Web/UI/WebControls/THiddenField.php +++ b/framework/Web/UI/WebControls/THiddenField.php @@ -1,117 +1,117 @@ -<?php
-/**
- * THiddenField class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.xisc.com/
+<?php +/** + * THiddenField class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.xisc.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THiddenField class
- *
- * THiddenField displays a hidden input field on a Web page.
- * The value of the input field can be accessed via {@link getValue Value} property.
- * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
- * event will be raised.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
-{
- private $_dataChanged=false;
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * THiddenField class + * + * THiddenField displays a hidden input field on a Web page. + * The value of the input field can be accessed via {@link getValue Value} property. + * If upon postback the value is changed, a {@link onValueChanged OnValueChanged} + * event will be raised. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer +{ + private $_dataChanged=false; private $_isValid=true; -
- /**
- * @return string tag name of the hidden field.
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets focus to this control.
- * This method overrides the parent implementation by forbidding setting focus to this control.
- */
- public function focus()
- {
- throw new TNotSupportedException('hiddenfield_focus_unsupported');
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by rendering
- * the hidden field input element.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $uniqueID=$this->getUniqueID();
- $this->getPage()->ensureRenderInForm($this);
- $writer->addAttribute('type','hidden');
- if($uniqueID!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getID()!=='')
- $writer->addAttribute('id',$this->getClientID());
- if(($value=$this->getValue())!=='')
- $writer->addAttribute('value',$value);
-
- if($this->getHasAttributes())
- {
- foreach($this->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
-
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Loads hidden field data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=$values[$key];
- if($value===$this->getValue())
- return false;
- else
- {
- $this->setValue($value);
- return $this->_dataChanged=true;
- }
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getValue();
- }
-
+ + /** + * @return string tag name of the hidden field. + */ + protected function getTagName() + { + return 'input'; + } + + /** + * Sets focus to this control. + * This method overrides the parent implementation by forbidding setting focus to this control. + */ + public function focus() + { + throw new TNotSupportedException('hiddenfield_focus_unsupported'); + } + + /** + * Renders the control. + * This method overrides the parent implementation by rendering + * the hidden field input element. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + $uniqueID=$this->getUniqueID(); + $this->getPage()->ensureRenderInForm($this); + $writer->addAttribute('type','hidden'); + if($uniqueID!=='') + $writer->addAttribute('name',$uniqueID); + if($this->getID()!=='') + $writer->addAttribute('id',$this->getClientID()); + if(($value=$this->getValue())!=='') + $writer->addAttribute('value',$value); + + if($this->getHasAttributes()) + { + foreach($this->getAttributes() as $name=>$value) + $writer->addAttribute($name,$value); + } + + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * Loads hidden field data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + $value=$values[$key]; + if($value===$this->getValue()) + return false; + else + { + $this->setValue($value); + return $this->_dataChanged=true; + } + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getValue(); + } + /** * Returns true if this control validated successfully. * Defaults to true. @@ -129,96 +129,96 @@ class THiddenField extends TControl implements IPostBackDataHandler, IValidatabl $this->_isValid=TPropertyValue::ensureBoolean($value); } - /**
- * Raises postdata changed event.
- * This method calls {@link onValueChanged} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onValueChanged(null);
- }
-
- /**
- * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
- * The method raises 'OnValueChanged' event to fire up the event delegates.
- * If you override this method, be sure to call the parent implementation
- * so that the attached event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onValueChanged($param)
- {
- $this->raiseEvent('OnValueChanged',$this,$param);
- }
-
- /**
- * @return string the value of the THiddenField
- */
- public function getValue()
- {
- return $this->getViewState('Value','');
- }
-
- /**
- * Sets the value of the THiddenField
- * @param string the value to be set
- */
- public function setValue($value)
- {
- $this->setViewState('Value',$value,'');
- }
-
- /**
- * Returns the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getValue()}.
- * @return string value of the hidden field
- * @see getValue
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getValue();
- }
-
- /**
- * Sets the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setValue()}.
- * @param string value of the hidden field
- * @see setValue
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setValue($value);
- }
-
-
- /**
- * @return boolean whether theming is enabled for this control. Defaults to false.
- */
- public function getEnableTheming()
- {
- return false;
- }
-
- /**
- * @param boolean whether theming is enabled for this control.
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('hiddenfield_theming_unsupported');
- }
-
- /**
- * @param string Skin ID
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setSkinID($value)
- {
- throw new TNotSupportedException('hiddenfield_skinid_unsupported');
- }
-}
-
+ /** + * Raises postdata changed event. + * This method calls {@link onValueChanged} method. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onValueChanged(null); + } + + /** + * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server. + * The method raises 'OnValueChanged' event to fire up the event delegates. + * If you override this method, be sure to call the parent implementation + * so that the attached event handlers can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onValueChanged($param) + { + $this->raiseEvent('OnValueChanged',$this,$param); + } + + /** + * @return string the value of the THiddenField + */ + public function getValue() + { + return $this->getViewState('Value',''); + } + + /** + * Sets the value of the THiddenField + * @param string the value to be set + */ + public function setValue($value) + { + $this->setViewState('Value',$value,''); + } + + /** + * Returns the value of the hidden field. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getValue()}. + * @return string value of the hidden field + * @see getValue + * @since 3.1.0 + */ + public function getData() + { + return $this->getValue(); + } + + /** + * Sets the value of the hidden field. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setValue()}. + * @param string value of the hidden field + * @see setValue + * @since 3.1.0 + */ + public function setData($value) + { + $this->setValue($value); + } + + + /** + * @return boolean whether theming is enabled for this control. Defaults to false. + */ + public function getEnableTheming() + { + return false; + } + + /** + * @param boolean whether theming is enabled for this control. + * @throws TNotSupportedException This method is always thrown when calling this method. + */ + public function setEnableTheming($value) + { + throw new TNotSupportedException('hiddenfield_theming_unsupported'); + } + + /** + * @param string Skin ID + * @throws TNotSupportedException This method is always thrown when calling this method. + */ + public function setSkinID($value) + { + throw new TNotSupportedException('hiddenfield_skinid_unsupported'); + } +} + diff --git a/framework/Web/UI/WebControls/THtmlElement.php b/framework/Web/UI/WebControls/THtmlElement.php index 3889ee50..29cd0057 100644 --- a/framework/Web/UI/WebControls/THtmlElement.php +++ b/framework/Web/UI/WebControls/THtmlElement.php @@ -1,68 +1,68 @@ -<?php
-/**
- * THtmlElement class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TWebControl');
-
-/**
- * THtmlElement class.
- *
- * THtmlElement represents a generic HTML element whose tag name is specified
- * via {@link setTagName TagName} property. Because THtmlElement extends from
- * {@link TWebControl}, it enjoys all its functionalities.
- *
- * To change the default tag your subclass should override {@link getDefaultTagName}
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @author Brad Anderson <javalizard@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-class THtmlElement extends TWebControl
-{
- /**
- * @var the tag of this element
- */
- private $_tagName=null;
-
- /**
- * @return string the tag name of this control. Defaults to 'span'.
- */
- public function getTagName()
- {
- return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
- }
-
- /**
- * @param string the tag name of this control.
- */
- public function setTagName($value)
- {
- $this->_tagName=TPropertyValue::ensureString($value);
- }
-
- /**
- * This is the default tag when no other is specified
- * @return string the default tag
- */
- public function getDefaultTagName() {
- return 'span';
- }
-
- /**
- * This tells you if this TagName has deviated from the original
- * @return boolean true if TagName has deviated from the default.
- */
- public function getIsMutated() {
- return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
- }
-}
+<?php +/** + * THtmlElement class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TWebControl'); + +/** + * THtmlElement class. + * + * THtmlElement represents a generic HTML element whose tag name is specified + * via {@link setTagName TagName} property. Because THtmlElement extends from + * {@link TWebControl}, it enjoys all its functionalities. + * + * To change the default tag your subclass should override {@link getDefaultTagName} + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @author Brad Anderson <javalizard@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ +class THtmlElement extends TWebControl +{ + /** + * @var the tag of this element + */ + private $_tagName=null; + + /** + * @return string the tag name of this control. Defaults to 'span'. + */ + public function getTagName() + { + return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName()); + } + + /** + * @param string the tag name of this control. + */ + public function setTagName($value) + { + $this->_tagName=TPropertyValue::ensureString($value); + } + + /** + * This is the default tag when no other is specified + * @return string the default tag + */ + public function getDefaultTagName() { + return 'span'; + } + + /** + * This tells you if this TagName has deviated from the original + * @return boolean true if TagName has deviated from the default. + */ + public function getIsMutated() { + return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName(); + } +} diff --git a/framework/Web/UI/WebControls/THyperLink.php b/framework/Web/UI/WebControls/THyperLink.php index 1e32d6c9..b745f7b0 100644 --- a/framework/Web/UI/WebControls/THyperLink.php +++ b/framework/Web/UI/WebControls/THyperLink.php @@ -1,227 +1,227 @@ -<?php
-/**
- * THyperLink class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.xisc.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THyperLink class
- *
- * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
- * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
- * the {@link setText Text} property. It is also possible to display an image
- * by setting the {@link setImageUrl ImageUrl} property. In this case,
- * {@link getText Text} is displayed as the alternate text of the image.
- * The link target is specified via the {@link setTarget Target} property.
- * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
- * the content enclosed within the control tag will be rendered.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLink extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name of the hyperlink
- */
- protected function getTagName()
- {
- return 'a';
- }
-
- /**
- * Adds attributes related to a hyperlink element to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $isEnabled=$this->getEnabled(true);
- if($this->getEnabled() && !$isEnabled)
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
- $writer->addAttribute('href',$url);
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
-
- /**
- * Renders the body content of the hyperlink.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($imageUrl=$this->getImageUrl())==='')
- {
- if(($text=$this->getText())!=='')
- $writer->write(THttpUtility::htmlEncode($text));
- else if($this->getHasControls())
- parent::renderContents($writer);
- else
- $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
- }
- else
- {
- $this->createImage($imageUrl)->renderControl($writer);
- }
- }
-
- /**
- * Gets the TImage for rendering the ImageUrl property. This is not for
- * creating dynamic images.
- * @param string image url.
- * @return TImage image control for rendering.
- */
- protected function createImage($imageUrl)
- {
- $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
- $image->setImageUrl($imageUrl);
- if(($width=$this->getImageWidth())!=='')
- $image->setWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $image->setHeight($height);
- if(($toolTip=$this->getToolTip())!=='')
- $image->setToolTip($toolTip);
- if(($text=$this->getText())!=='')
- $image->setAlternateText($text);
- $image->setBorderWidth('0');
- return $image;
- }
-
- /**
- * @return string the text caption of the THyperLink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the THyperLink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * Sets the height of the image in the THyperLink
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewSTate('ImageHeight',$value,'');
- }
-
- /**
- * @return string the location of the image file for the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * Sets the location of image file of the THyperLink.
- * @param string the image file location
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * Sets the width of the image in the THyperLink
- * @param string width of the image
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the THyperLink component is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * Returns the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text caption
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text caption to be set
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-}
-
+<?php +/** + * THyperLink class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.xisc.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * THyperLink class + * + * THyperLink displays a hyperlink on a page. The hyperlink URL is specified + * via the {@link setNavigateUrl NavigateUrl} property, and link text is via + * the {@link setText Text} property. It is also possible to display an image + * by setting the {@link setImageUrl ImageUrl} property. In this case, + * {@link getText Text} is displayed as the alternate text of the image. + * The link target is specified via the {@link setTarget Target} property. + * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty, + * the content enclosed within the control tag will be rendered. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THyperLink extends TWebControl implements IDataRenderer +{ + /** + * @return string tag name of the hyperlink + */ + protected function getTagName() + { + return 'a'; + } + + /** + * Adds attributes related to a hyperlink element to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $isEnabled=$this->getEnabled(true); + if($this->getEnabled() && !$isEnabled) + $writer->addAttribute('disabled','disabled'); + parent::addAttributesToRender($writer); + if(($url=$this->getNavigateUrl())!=='' && $isEnabled) + $writer->addAttribute('href',$url); + if(($target=$this->getTarget())!=='') + $writer->addAttribute('target',$target); + } + + /** + * Renders the body content of the hyperlink. + * @param THtmlWriter the writer for rendering + */ + public function renderContents($writer) + { + if(($imageUrl=$this->getImageUrl())==='') + { + if(($text=$this->getText())!=='') + $writer->write(THttpUtility::htmlEncode($text)); + else if($this->getHasControls()) + parent::renderContents($writer); + else + $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl())); + } + else + { + $this->createImage($imageUrl)->renderControl($writer); + } + } + + /** + * Gets the TImage for rendering the ImageUrl property. This is not for + * creating dynamic images. + * @param string image url. + * @return TImage image control for rendering. + */ + protected function createImage($imageUrl) + { + $image=Prado::createComponent('System.Web.UI.WebControls.TImage'); + $image->setImageUrl($imageUrl); + if(($width=$this->getImageWidth())!=='') + $image->setWidth($width); + if(($height=$this->getImageHeight())!=='') + $image->setHeight($height); + if(($toolTip=$this->getToolTip())!=='') + $image->setToolTip($toolTip); + if(($text=$this->getText())!=='') + $image->setAlternateText($text); + $image->setBorderWidth('0'); + return $image; + } + + /** + * @return string the text caption of the THyperLink + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the THyperLink. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string height of the image in the THyperLink + */ + public function getImageHeight() + { + return $this->getViewState('ImageHeight',''); + } + + /** + * Sets the height of the image in the THyperLink + * @param string height of the image in the THyperLink + */ + public function setImageHeight($value) + { + $this->setViewSTate('ImageHeight',$value,''); + } + + /** + * @return string the location of the image file for the THyperLink + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * Sets the location of image file of the THyperLink. + * @param string the image file location + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * @return string width of the image in the THyperLink + */ + public function getImageWidth() + { + return $this->getViewState('ImageWidth',''); + } + + /** + * Sets the width of the image in the THyperLink + * @param string width of the image + */ + public function setImageWidth($value) + { + $this->setViewState('ImageWidth',$value,''); + } + + /** + * @return string the URL to link to when the THyperLink component is clicked. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL to link to when the THyperLink component is clicked. + * @param string the URL + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',$value,''); + } + + /** + * Returns the URL to link to when the THyperLink component is clicked. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text caption + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the URL to link to when the THyperLink component is clicked. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text caption to be set + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked. + * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. + */ + public function setTarget($value) + { + $this->setViewState('Target',$value,''); + } +} + diff --git a/framework/Web/UI/WebControls/THyperLinkColumn.php b/framework/Web/UI/WebControls/THyperLinkColumn.php index a73880f1..faa4ce42 100644 --- a/framework/Web/UI/WebControls/THyperLinkColumn.php +++ b/framework/Web/UI/WebControls/THyperLinkColumn.php @@ -1,273 +1,273 @@ -<?php
-/**
- * THyperLinkColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-/**
- * THyperLink class file
- */
-Prado::using('System.Web.UI.WebControls.THyperLink');
-
-/**
- * THyperLinkColumn class
- *
- * THyperLinkColumn contains a hyperlink for each item in the column.
- * You can set the text and the url of the hyperlink by {@link setText Text}
- * and {@link setNavigateUrl NavigateUrl} properties, respectively.
- * You can also bind the text and url to specific data field in datasource
- * by setting {@link setDataTextField DataTextField} and
- * {@link setDataNavigateUrlField DataNavigateUrlField}.
- * Both can be formatted before rendering according to the
- * {@link setDataTextFormatString DataTextFormatString} and
- * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
- * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
- * are present, the latter takes precedence.
- * The same rule applies to {@link setNavigateUrl NavigateUrl} and
- * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
- *
- * The hyperlinks in the column can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->HyperLinkColumnID->HyperLink
- * $datagridItem->HyperLinkColumnID->Controls[0]
- * </code>
- * The second method is possible because the hyperlink control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLinkColumn extends TDataGridColumn
-{
- /**
- * @return string the text caption of the hyperlink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the hyperlink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the hyperlink caption
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the hyperlink caption
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewState('ImageHeight',$value,'');
- }
-
- /**
- * @return string url of the image in the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string url of the image in the THyperLink
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * @param string width of the image in the THyperLink
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the hyperlink is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the hyperlink is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function getDataNavigateUrlField()
- {
- return $this->getViewState('DataNavigateUrlField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function setDataNavigateUrlField($value)
- {
- $this->setViewState('DataNavigateUrlField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function getDataNavigateUrlFormatString()
- {
- return $this->getViewState('DataNavigateUrlFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function setDataNavigateUrlFormatString($value)
- {
- $this->setViewState('DataNavigateUrlFormatString',$value,'');
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a hyperlink within the cell.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $link=new THyperLink;
- if(($url = $this->getImageUrl())!=='')
- {
- $link->setImageUrl($url);
- if(($width=$this->getImageWidth())!=='')
- $link->setImageWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $link->setImageHeight($height);
- }
- $link->setText($this->getText());
- $link->setNavigateUrl($this->getNavigateUrl());
- $link->setTarget($this->getTarget());
- if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
- $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- $cell->getControls()->add($link);
- $cell->registerObject('HyperLink',$link);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($field=$this->getDataTextField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
- $sender->setText($text);
- }
- if(($field=$this->getDataNavigateUrlField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
- $sender->setNavigateUrl($url);
- }
- }
-}
-
+<?php +/** + * THyperLinkColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); +/** + * THyperLink class file + */ +Prado::using('System.Web.UI.WebControls.THyperLink'); + +/** + * THyperLinkColumn class + * + * THyperLinkColumn contains a hyperlink for each item in the column. + * You can set the text and the url of the hyperlink by {@link setText Text} + * and {@link setNavigateUrl NavigateUrl} properties, respectively. + * You can also bind the text and url to specific data field in datasource + * by setting {@link setDataTextField DataTextField} and + * {@link setDataNavigateUrlField DataNavigateUrlField}. + * Both can be formatted before rendering according to the + * {@link setDataTextFormatString DataTextFormatString} and + * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString} + * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField} + * are present, the latter takes precedence. + * The same rule applies to {@link setNavigateUrl NavigateUrl} and + * {@link setDataNavigateUrlField DataNavigateUrlField} properties. + * + * The hyperlinks in the column can be accessed by one of the following two methods: + * <code> + * $datagridItem->HyperLinkColumnID->HyperLink + * $datagridItem->HyperLinkColumnID->Controls[0] + * </code> + * The second method is possible because the hyperlink control created within the + * datagrid cell is the first child. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THyperLinkColumn extends TDataGridColumn +{ + /** + * @return string the text caption of the hyperlink + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text caption of the hyperlink. + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return string the field name from the data source to bind to the hyperlink caption + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * @param string the field name from the data source to bind to the hyperlink caption + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how the hyperlink caption will be displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * @param string the formatting string used to control how the hyperlink caption will be displayed. + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string height of the image in the THyperLink + */ + public function getImageHeight() + { + return $this->getViewState('ImageHeight',''); + } + + /** + * @param string height of the image in the THyperLink + */ + public function setImageHeight($value) + { + $this->setViewState('ImageHeight',$value,''); + } + + /** + * @return string url of the image in the THyperLink + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * @param string url of the image in the THyperLink + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * @return string width of the image in the THyperLink + */ + public function getImageWidth() + { + return $this->getViewState('ImageWidth',''); + } + + /** + * @param string width of the image in the THyperLink + */ + public function setImageWidth($value) + { + $this->setViewState('ImageWidth',$value,''); + } + + /** + * @return string the URL to link to when the hyperlink is clicked. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * Sets the URL to link to when the hyperlink is clicked. + * @param string the URL + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',$value,''); + } + + /** + * @return string the field name from the data source to bind to the navigate url of hyperlink + */ + public function getDataNavigateUrlField() + { + return $this->getViewState('DataNavigateUrlField',''); + } + + /** + * @param string the field name from the data source to bind to the navigate url of hyperlink + */ + public function setDataNavigateUrlField($value) + { + $this->setViewState('DataNavigateUrlField',$value,''); + } + + /** + * @return string the formatting string used to control how the navigate url of hyperlink will be displayed. + */ + public function getDataNavigateUrlFormatString() + { + return $this->getViewState('DataNavigateUrlFormatString',''); + } + + /** + * @param string the formatting string used to control how the navigate url of hyperlink will be displayed. + */ + public function setDataNavigateUrlFormatString($value) + { + $this->setViewState('DataNavigateUrlFormatString',$value,''); + } + + /** + * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked. + * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string. + */ + public function setTarget($value) + { + $this->setViewState('Target',$value,''); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It creates a hyperlink within the cell. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + $link=new THyperLink; + if(($url = $this->getImageUrl())!=='') + { + $link->setImageUrl($url); + if(($width=$this->getImageWidth())!=='') + $link->setImageWidth($width); + if(($height=$this->getImageHeight())!=='') + $link->setImageHeight($height); + } + $link->setText($this->getText()); + $link->setNavigateUrl($this->getNavigateUrl()); + $link->setTarget($this->getTarget()); + if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='') + $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + $cell->getControls()->add($link); + $cell->registerObject('HyperLink',$link); + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + if(($field=$this->getDataTextField())!=='') + { + $value=$this->getDataFieldValue($data,$field); + $text=$this->formatDataValue($this->getDataTextFormatString(),$value); + $sender->setText($text); + } + if(($field=$this->getDataNavigateUrlField())!=='') + { + $value=$this->getDataFieldValue($data,$field); + $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value); + $sender->setNavigateUrl($url); + } + } +} + diff --git a/framework/Web/UI/WebControls/TImage.php b/framework/Web/UI/WebControls/TImage.php index 37f9a050..c8dde281 100644 --- a/framework/Web/UI/WebControls/TImage.php +++ b/framework/Web/UI/WebControls/TImage.php @@ -1,157 +1,157 @@ -<?php
-/**
- * TImage class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TImage class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TImage class
- *
- * TImage displays an image on a page. The image is specified via the
- * {@link setImageUrl ImageUrl} property which takes a relative or absolute
- * URL to the image file. The alignment of the image displayed is set by
- * the {@link setImageAlign ImageAlign} property. To set alternative texts
- * or long description of the image, use {@link setAlternateText AlternateText}
- * or {@link setDescriptionUrl DescriptionUrl} property, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImage extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name of image control
- */
- protected function getTagName()
- {
- return 'img';
- }
-
- /**
- * Adds attributes related to an HTML image element to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('src',$this->getImageUrl());
- $writer->addAttribute('alt',$this->getAlternateText());
- if(($desc=$this->getDescriptionUrl())!=='')
- $writer->addAttribute('longdesc',$desc);
- if(($align=$this->getImageAlign())!=='')
- $writer->addAttribute('align',$align);
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the body content of the image.
- * Nothing to be rendered within image tags.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- }
-
- /**
- * @return string the alternative text displayed in the TImage component when the image is unavailable.
- */
- public function getAlternateText()
- {
- return $this->getViewState('AlternateText','');
- }
-
- /**
- * Sets the alternative text to be displayed in the TImage when the image is unavailable.
- * @param string the alternative text
- */
- public function setAlternateText($value)
- {
- $this->setViewState('AlternateText',$value,'');
- }
-
- /**
- * @return string the alignment of the image with respective to other elements on the page, defaults to empty.
- */
- public function getImageAlign()
- {
- return $this->getViewState('ImageAlign','');
- }
-
- /**
- * Sets the alignment of the image with respective to other elements on the page.
- * Possible values include: absbottom, absmiddle, baseline, bottom, left,
- * middle, right, texttop, and top. If an empty string is passed in,
- * imagealign attribute will not be rendered.
- * @param string the alignment of the image
- */
- public function setImageAlign($value)
- {
- $this->setViewState('ImageAlign',$value,'');
- }
-
- /**
- * @return string the URL of the image file
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string the URL of the image file
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * Returns the URL of the image file.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getImageUrl()}.
- * @return string the URL of the image file.
- * @see getImageUrl
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getImageUrl();
- }
-
- /**
- * Sets the URL of the image.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setImageUrl()}.
- * @param string the URL of the image file.
- * @see setImageUrl
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setImageUrl($value);
- }
-
- /**
- * @return string the URL to long description
- */
- public function getDescriptionUrl()
- {
- return $this->getViewState('DescriptionUrl','');
- }
-
- /**
- * @param string the URL to the long description of the image.
- */
- public function setDescriptionUrl($value)
- {
- $this->setViewState('DescriptionUrl',$value,'');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TImage class + * + * TImage displays an image on a page. The image is specified via the + * {@link setImageUrl ImageUrl} property which takes a relative or absolute + * URL to the image file. The alignment of the image displayed is set by + * the {@link setImageAlign ImageAlign} property. To set alternative texts + * or long description of the image, use {@link setAlternateText AlternateText} + * or {@link setDescriptionUrl DescriptionUrl} property, respectively. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TImage extends TWebControl implements IDataRenderer +{ + /** + * @return string tag name of image control + */ + protected function getTagName() + { + return 'img'; + } + + /** + * Adds attributes related to an HTML image element to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $writer->addAttribute('src',$this->getImageUrl()); + $writer->addAttribute('alt',$this->getAlternateText()); + if(($desc=$this->getDescriptionUrl())!=='') + $writer->addAttribute('longdesc',$desc); + if(($align=$this->getImageAlign())!=='') + $writer->addAttribute('align',$align); + parent::addAttributesToRender($writer); + } + + /** + * Renders the body content of the image. + * Nothing to be rendered within image tags. + * @param THtmlWriter the writer for rendering + */ + public function renderContents($writer) + { + } + + /** + * @return string the alternative text displayed in the TImage component when the image is unavailable. + */ + public function getAlternateText() + { + return $this->getViewState('AlternateText',''); + } + + /** + * Sets the alternative text to be displayed in the TImage when the image is unavailable. + * @param string the alternative text + */ + public function setAlternateText($value) + { + $this->setViewState('AlternateText',$value,''); + } + + /** + * @return string the alignment of the image with respective to other elements on the page, defaults to empty. + */ + public function getImageAlign() + { + return $this->getViewState('ImageAlign',''); + } + + /** + * Sets the alignment of the image with respective to other elements on the page. + * Possible values include: absbottom, absmiddle, baseline, bottom, left, + * middle, right, texttop, and top. If an empty string is passed in, + * imagealign attribute will not be rendered. + * @param string the alignment of the image + */ + public function setImageAlign($value) + { + $this->setViewState('ImageAlign',$value,''); + } + + /** + * @return string the URL of the image file + */ + public function getImageUrl() + { + return $this->getViewState('ImageUrl',''); + } + + /** + * @param string the URL of the image file + */ + public function setImageUrl($value) + { + $this->setViewState('ImageUrl',$value,''); + } + + /** + * Returns the URL of the image file. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getImageUrl()}. + * @return string the URL of the image file. + * @see getImageUrl + * @since 3.1.0 + */ + public function getData() + { + return $this->getImageUrl(); + } + + /** + * Sets the URL of the image. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setImageUrl()}. + * @param string the URL of the image file. + * @see setImageUrl + * @since 3.1.0 + */ + public function setData($value) + { + $this->setImageUrl($value); + } + + /** + * @return string the URL to long description + */ + public function getDescriptionUrl() + { + return $this->getViewState('DescriptionUrl',''); + } + + /** + * @param string the URL to the long description of the image. + */ + public function setDescriptionUrl($value) + { + $this->setViewState('DescriptionUrl',$value,''); + } +} + diff --git a/framework/Web/UI/WebControls/TImageButton.php b/framework/Web/UI/WebControls/TImageButton.php index 350c84d4..a92a9df8 100644 --- a/framework/Web/UI/WebControls/TImageButton.php +++ b/framework/Web/UI/WebControls/TImageButton.php @@ -1,442 +1,442 @@ -<?php
-/**
- * TImageButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TImageButton class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TImage class file
- */
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TImageButton class
- *
- * TImageButton creates an image button on the page. It is used to submit data to a page.
- * You can create either a <b>submit</b> button or a <b>command</b> button.
- *
- * A <b>command</b> button has a command name (specified by
- * the {@link setCommandName CommandName} property) and and a command parameter
- * (specified by {@link setCommandParameter CommandParameter} property)
- * associated with the button. This allows you to create multiple TLinkButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter. You can provide an event handler for
- * {@link onCommand OnCommand} event to programmatically control the actions performed
- * when the command button is clicked. In the event handler, you can determine
- * the {@link setCommandName CommandName} property value and
- * the {@link setCommandParameter CommandParameter} property value
- * through the {@link TCommandParameter::getName Name} and
- * {@link TCommandParameter::getParameter Parameter} properties of the event
- * parameter which is of type {@link TCommandEventParameter}.
- *
- * A <b>submit</b> button does not have a command name associated with the button
- * and clicking on it simply posts the Web page back to the server.
- * By default, a TImageButton control is a submit button.
- * You can provide an event handler for the {@link onClick OnClick} event
- * to programmatically control the actions performed when the submit button is clicked.
- * The coordinates of the clicking point can be obtained from the {@link onClick OnClick}
- * event parameter, which is of type {@link TImageClickEventParameter}.
- *
- * Clicking on button can trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * And the validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TImageButton displays the {@link setText Text} property as the hint text to the displayed image.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageButton extends TImage implements IPostBackDataHandler, IPostBackEventHandler, IButtonControl
-{
- /**
- * @var integer x coordinate that the image is being clicked at
- */
- private $_x=0;
- /**
- * @var integer y coordinate that the image is being clicked at
- */
- private $_y=0;
- private $_dataChanged=false;
-
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- $writer->addAttribute('type','image');
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getEnabled(true))
- {
- if($this->getEnableClientScript() && $this->needPostBackScript())
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TImageButton';
- }
-
- /**
- * @return boolean whether to perform validation if the button is clicked
- */
- protected function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * @return boolean whether the button needs javascript to do postback
- */
- protected function needPostBackScript()
- {
- return $this->canCauseValidation() || $this->getIsDefaultButton();
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['EventTarget'] = $this->getUniqueID();
-
- return $options;
- }
-
- /**
- * This method checks if the TImageButton is clicked and loads the coordinates of the clicking position.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $uid=$this->getUniqueID();
- if(isset($values["{$uid}_x"]) && isset($values["{$uid}_y"]))
- {
- $this->_x=intval($values["{$uid}_x"]);
- $this->_y=intval($values["{$uid}_y"]);
- if($this->getPage()->getPostBackEventTarget()===null)
- $this->getPage()->setPostBackEventTarget($this);
- $this->_dataChanged=true;
- }
- return false;
- }
-
- /**
- * A dummy implementation for the IPostBackDataHandler interface.
- */
- public function raisePostDataChangedEvent()
- {
- // no post data to handle
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TImageClickEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(new TImageClickEventParameter($this->_x,$this->_y));
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string caption of the button
- */
- public function getText()
- {
- return $this->getAlternateText();
- }
-
- /**
- * @param string caption of the button
- */
- public function setText($value)
- {
- $this->setAlternateText($value);
- }
-
- /**
- * Registers the image button to receive postback data during postback.
- * This is necessary because an image button, when postback, does not have
- * direct mapping between post data and the image button name.
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * This overrides the parent implementation with nothing to be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- }
-}
-
-/**
- * TImageClickEventParameter class
- *
- * TImageClickEventParameter encapsulates the parameter data for
- * {@link TImageButton::onClick Click} event of {@link TImageButton} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageClickEventParameter extends TEventParameter
-{
- /**
- * the X coordinate of the clicking point
- * @var integer
- */
- private $_x=0;
- /**
- * the Y coordinate of the clicking point
- * @var integer
- */
- private $_y=0;
-
- /**
- * Constructor.
- * @param integer X coordinate of the clicking point
- * @param integer Y coordinate of the clicking point
- */
- public function __construct($x,$y)
- {
- $this->_x=$x;
- $this->_y=$y;
- }
-
- /**
- * @return integer X coordinate of the clicking point, defaults to 0
- */
- public function getX()
- {
- return $this->_x;
- }
-
- /**
- * @param integer X coordinate of the clicking point
- */
- public function setX($value)
- {
- $this->_x=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return integer Y coordinate of the clicking point, defaults to 0
- */
- public function getY()
- {
- return $this->_y;
- }
-
- /**
- * @param integer Y coordinate of the clicking point
- */
- public function setY($value)
- {
- $this->_y=TPropertyValue::ensureInteger($value);
- }
-}
-
-?>
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TImage class file + */ +Prado::using('System.Web.UI.WebControls.TImage'); + +/** + * TImageButton class + * + * TImageButton creates an image button on the page. It is used to submit data to a page. + * You can create either a <b>submit</b> button or a <b>command</b> button. + * + * A <b>command</b> button has a command name (specified by + * the {@link setCommandName CommandName} property) and and a command parameter + * (specified by {@link setCommandParameter CommandParameter} property) + * associated with the button. This allows you to create multiple TLinkButton + * components on a Web page and programmatically determine which one is clicked + * with what parameter. You can provide an event handler for + * {@link onCommand OnCommand} event to programmatically control the actions performed + * when the command button is clicked. In the event handler, you can determine + * the {@link setCommandName CommandName} property value and + * the {@link setCommandParameter CommandParameter} property value + * through the {@link TCommandParameter::getName Name} and + * {@link TCommandParameter::getParameter Parameter} properties of the event + * parameter which is of type {@link TCommandEventParameter}. + * + * A <b>submit</b> button does not have a command name associated with the button + * and clicking on it simply posts the Web page back to the server. + * By default, a TImageButton control is a submit button. + * You can provide an event handler for the {@link onClick OnClick} event + * to programmatically control the actions performed when the submit button is clicked. + * The coordinates of the clicking point can be obtained from the {@link onClick OnClick} + * event parameter, which is of type {@link TImageClickEventParameter}. + * + * Clicking on button can trigger form validation, if + * {@link setCausesValidation CausesValidation} is true. + * And the validation may be restricted within a certain group of validator + * controls by setting {@link setValidationGroup ValidationGroup} property. + * If validation is successful, the data will be post back to the same page. + * + * TImageButton displays the {@link setText Text} property as the hint text to the displayed image. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TImageButton extends TImage implements IPostBackDataHandler, IPostBackEventHandler, IButtonControl +{ + /** + * @var integer x coordinate that the image is being clicked at + */ + private $_x=0; + /** + * @var integer y coordinate that the image is being clicked at + */ + private $_y=0; + private $_dataChanged=false; + + /** + * @return string tag name of the button + */ + protected function getTagName() + { + return 'input'; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Adds attribute name-value pairs to renderer. + * This overrides the parent implementation with additional button specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $page=$this->getPage(); + $page->ensureRenderInForm($this); + $writer->addAttribute('type','image'); + if(($uniqueID=$this->getUniqueID())!=='') + $writer->addAttribute('name',$uniqueID); + if($this->getEnabled(true)) + { + if($this->getEnableClientScript() && $this->needPostBackScript()) + $this->renderClientControlScript($writer); + } + else if($this->getEnabled()) // in this case, parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + parent::addAttributesToRender($writer); + } + + /** + * Renders the client-script code. + */ + protected function renderClientControlScript($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TImageButton'; + } + + /** + * @return boolean whether to perform validation if the button is clicked + */ + protected function canCauseValidation() + { + if($this->getCausesValidation()) + { + $group=$this->getValidationGroup(); + return $this->getPage()->getValidators($group)->getCount()>0; + } + else + return false; + } + + /** + * @param boolean set by a panel to register this button as the default button for the panel. + */ + public function setIsDefaultButton($value) + { + $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean true if this button is registered as a default button for a panel. + */ + public function getIsDefaultButton() + { + return $this->getViewState('IsDefaultButton', false); + } + + /** + * @return boolean whether the button needs javascript to do postback + */ + protected function needPostBackScript() + { + return $this->canCauseValidation() || $this->getIsDefaultButton(); + } + + /** + * Returns postback specifications for the button. + * This method is used by framework and control developers. + * @return array parameters about how the button defines its postback behavior. + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['EventTarget'] = $this->getUniqueID(); + + return $options; + } + + /** + * This method checks if the TImageButton is clicked and loads the coordinates of the clicking position. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + $uid=$this->getUniqueID(); + if(isset($values["{$uid}_x"]) && isset($values["{$uid}_y"])) + { + $this->_x=intval($values["{$uid}_x"]); + $this->_y=intval($values["{$uid}_y"]); + if($this->getPage()->getPostBackEventTarget()===null) + $this->getPage()->setPostBackEventTarget($this); + $this->_dataChanged=true; + } + return false; + } + + /** + * A dummy implementation for the IPostBackDataHandler interface. + */ + public function raisePostDataChangedEvent() + { + // no post data to handle + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnClick' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handler can be invoked. + * @param TImageClickEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param) + { + $this->raiseEvent('OnClick',$this,$param); + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnCommand' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TCommandEventParameter event parameter to be passed to the event handlers + */ + public function onCommand($param) + { + $this->raiseEvent('OnCommand',$this,$param); + $this->raiseBubbleEvent($this,$param); + } + + /** + * Raises the postback event. + * This method is required by {@link IPostBackEventHandler} interface. + * If {@link getCausesValidation CausesValidation} is true, it will + * invoke the page's {@link TPage::validate validate} method first. + * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events. + * This method is mainly used by framework and control developers. + * @param TEventParameter the event parameter + */ + public function raisePostBackEvent($param) + { + if($this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onClick(new TImageClickEventParameter($this->_x,$this->_y)); + $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter())); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * @return boolean whether postback event trigger by this button will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this button will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the command name associated with the {@link onCommand OnCommand} event. + */ + public function getCommandName() + { + return $this->getViewState('CommandName',''); + } + + /** + * @param string the command name associated with the {@link onCommand OnCommand} event. + */ + public function setCommandName($value) + { + $this->setViewState('CommandName',$value,''); + } + + /** + * @return string the parameter associated with the {@link onCommand OnCommand} event + */ + public function getCommandParameter() + { + return $this->getViewState('CommandParameter',''); + } + + /** + * @param string the parameter associated with the {@link onCommand OnCommand} event. + */ + public function setCommandParameter($value) + { + $this->setViewState('CommandParameter',$value,''); + } + + /** + * @return string the group of validators which the button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return string caption of the button + */ + public function getText() + { + return $this->getAlternateText(); + } + + /** + * @param string caption of the button + */ + public function setText($value) + { + $this->setAlternateText($value); + } + + /** + * Registers the image button to receive postback data during postback. + * This is necessary because an image button, when postback, does not have + * direct mapping between post data and the image button name. + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->getPage()->registerRequiresPostData($this); + } + + /** + * Renders the body content enclosed between the control tag. + * This overrides the parent implementation with nothing to be rendered. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + } +} + +/** + * TImageClickEventParameter class + * + * TImageClickEventParameter encapsulates the parameter data for + * {@link TImageButton::onClick Click} event of {@link TImageButton} controls. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TImageClickEventParameter extends TEventParameter +{ + /** + * the X coordinate of the clicking point + * @var integer + */ + private $_x=0; + /** + * the Y coordinate of the clicking point + * @var integer + */ + private $_y=0; + + /** + * Constructor. + * @param integer X coordinate of the clicking point + * @param integer Y coordinate of the clicking point + */ + public function __construct($x,$y) + { + $this->_x=$x; + $this->_y=$y; + } + + /** + * @return integer X coordinate of the clicking point, defaults to 0 + */ + public function getX() + { + return $this->_x; + } + + /** + * @param integer X coordinate of the clicking point + */ + public function setX($value) + { + $this->_x=TPropertyValue::ensureInteger($value); + } + + /** + * @return integer Y coordinate of the clicking point, defaults to 0 + */ + public function getY() + { + return $this->_y; + } + + /** + * @param integer Y coordinate of the clicking point + */ + public function setY($value) + { + $this->_y=TPropertyValue::ensureInteger($value); + } +} + +?> diff --git a/framework/Web/UI/WebControls/TImageMap.php b/framework/Web/UI/WebControls/TImageMap.php index 5907d03d..718a3414 100644 --- a/framework/Web/UI/WebControls/TImageMap.php +++ b/framework/Web/UI/WebControls/TImageMap.php @@ -1,837 +1,837 @@ -<?php
-/**
- * TImageMap and related class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TImageMap and related class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TImage class file
- */
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TImageMap class
- *
- * TImageMap represents an image on a page. Hotspot regions can be defined
- * within the image. Depending on the {@link setHotSpotMode HotSpotMode},
- * clicking on the hotspots may trigger a postback or navigate to a specified
- * URL. The hotspots defined may be accessed via {@link getHotSpots HotSpots}.
- * Each hotspot is described as a {@link THotSpot}, which can be a circle,
- * rectangle, polygon, etc. To add hotspot in a template, use the following,
- * <code>
- * <com:TImageMap>
- * <com:TCircleHotSpot ... />
- * <com:TRectangleHotSpot ... />
- * <com:TPolygonHotSpot ... />
- * </com:TImageMap>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageMap extends TImage implements IPostBackEventHandler
-{
- const MAP_NAME_PREFIX='ImageMap';
-
- /**
- * Processes an object that is created during parsing template.
- * This method adds {@link THotSpot} objects into the hotspot collection
- * of the imagemap.
- * @param string|TComponent text string or component parsed and instantiated in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof THotSpot)
- $this->getHotSpots()->add($object);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional imagemap specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if($this->getHotSpots()->getCount()>0)
- {
- $writer->addAttribute('usemap','#'.self::MAP_NAME_PREFIX.$this->getClientID());
- $writer->addAttribute('id',$this->getUniqueID());
- }
- if($this->getEnabled() && !$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Renders this imagemap.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- parent::render($writer);
-
- $hotspots=$this->getHotSpots();
-
- if($hotspots->getCount()>0)
- {
- $clientID=$this->getClientID();
- $cs=$this->getPage()->getClientScript();
- $writer->writeLine();
- $writer->addAttribute('name',self::MAP_NAME_PREFIX.$clientID);
- $writer->renderBeginTag('map');
- $writer->writeLine();
- if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=THotSpotMode::Navigate;
- $target=$this->getTarget();
- $i=0;
- $options['EventTarget'] = $this->getUniqueID();
- $options['StopEvent'] = true;
- $cs=$this->getPage()->getClientScript();
- foreach($hotspots as $hotspot)
- {
- if($hotspot->getHotSpotMode()===THotSpotMode::NotSet)
- $hotspot->setHotSpotMode($mode);
- if($target!=='' && $hotspot->getTarget()==='')
- $hotspot->setTarget($target);
- if($hotspot->getHotSpotMode()===THotSpotMode::PostBack)
- {
- $id=$clientID.'_'.$i;
- $writer->addAttribute('id',$id);
- $writer->addAttribute('href','#'.$id); //create unique no-op url references
- $options['ID']=$id;
- $options['EventParameter']="$i";
- $options['CausesValidation']=$hotspot->getCausesValidation();
- $options['ValidationGroup']=$hotspot->getValidationGroup();
- $cs->registerPostBackControl($this->getClientClassName(),$options);
- }
- $hotspot->render($writer);
- $writer->writeLine();
- $i++;
- }
- $writer->renderEndTag();
- }
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TImageMap';
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- $postBackValue=null;
- if($param!=='')
- {
- $index=TPropertyValue::ensureInteger($param);
- $hotspots=$this->getHotSpots();
- if($index>=0 && $index<$hotspots->getCount())
- {
- $hotspot=$hotspots->itemAt($index);
- if(($mode=$hotspot->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=$this->getHotSpotMode();
- if($mode===THotSpotMode::PostBack)
- {
- $postBackValue=$hotspot->getPostBackValue();
- if($hotspot->getCausesValidation())
- $this->getPage()->validate($hotspot->getValidationGroup());
- }
- }
- }
- if($postBackValue!==null)
- $this->onClick(new TImageMapEventParameter($postBackValue));
- }
-
- /**
- * @return THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. Defaults to THotSpotMode::NotSet.
- */
- public function getHotSpotMode()
- {
- return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
- }
-
- /**
- * Sets the behavior of hotspot regions in this imagemap when they are clicked.
- * If an individual hotspot has a mode other than 'NotSet', the mode set in this
- * imagemap will be ignored. By default, 'NotSet' is equivalent to 'Navigate'.
- * @param THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked.
- */
- public function setHotSpotMode($value)
- {
- $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
- }
-
- /**
- * @return THotSpotCollection collection of hotspots defined in this imagemap.
- */
- public function getHotSpots()
- {
- if(($hotspots=$this->getViewState('HotSpots',null))===null)
- {
- $hotspots=new THotSpotCollection;
- $this->setViewState('HotSpots',$hotspots);
- }
- return $hotspots;
- }
-
- /**
- * @return string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. Defaults to ''.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the new page when a hotspot region is clicked within the imagemap.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * Raises <b>OnClick</b> event.
- * This method is invoked when a hotspot region is clicked within the imagemap.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TImageMapEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-}
-
-/**
- * TImageMapEventParameter class.
- *
- * TImageMapEventParameter represents a postback event parameter
- * when a hotspot is clicked and posts back in a {@link TImageMap}.
- * To retrieve the post back value associated with the hotspot being clicked,
- * access {@link getPostBackValue PostBackValue}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageMapEventParameter extends TEventParameter
-{
- private $_postBackValue;
-
- /**
- * Constructor.
- * @param string post back value associated with the hotspot clicked
- */
- public function __construct($postBackValue)
- {
- $this->_postBackValue=$postBackValue;
- }
-
- /**
- * @return string post back value associated with the hotspot clicked
- */
- public function getPostBackValue()
- {
- return $this->_postBackValue;
- }
-}
-
-/**
- * THotSpotCollection class.
- *
- * THotSpotCollection represents a collection of hotspots in an imagemap.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THotSpotCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only {@link THotSpot}.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a THotSpot.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof THotSpot)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('hotspotcollection_hotspot_required');
- }
-}
-
-
-/**
- * THotSpot class.
- *
- * THotSpot implements the basic functionality common to all hot spot shapes.
- * Derived classes include {@link TCircleHotSpot}, {@link TPolygonHotSpot}
- * and {@link TRectangleHotSpot}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class THotSpot extends TComponent
-{
- private $_viewState=array();
-
- /**
- * Returns a viewstate value.
- *
- * This function is very useful in defining getter functions for component properties
- * that must be kept in viewstate.
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- protected function getViewState($key,$defaultValue=null)
- {
- return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in viewstate.
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- protected function setViewState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_viewState[$key]);
- else
- $this->_viewState[$key]=$value;
- }
-
- /**
- * @return string shape of the hotspot, can be 'circle', 'rect', 'poly', etc.
- */
- abstract public function getShape();
- /**
- * @return string coordinates defining the hotspot shape.
- */
- abstract public function getCoordinates();
-
- /**
- * @return string the access key that allows you to quickly navigate to the HotSpot region. Defaults to ''.
- */
- public function getAccessKey()
- {
- return $this->getViewState('AccessKey','');
- }
-
- /**
- * @param string the access key that allows you to quickly navigate to the HotSpot region.
- */
- public function setAccessKey($value)
- {
- $this->setViewState('AccessKey',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the alternate text to display for a HotSpot object. Defaults to ''.
- */
- public function getAlternateText()
- {
- return $this->getViewState('AlternateText','');
- }
-
- /**
- * @param string the alternate text to display for a HotSpot object.
- */
- public function setAlternateText($value)
- {
- $this->setViewState('AlternateText',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return THotSpotMode the behavior of a HotSpot object when it is clicked. Defaults to THotSpotMode::NotSet.
- */
- public function getHotSpotMode()
- {
- return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
- }
-
- /**
- * @param THotSpotMode the behavior of a HotSpot object when it is clicked.
- */
- public function setHotSpotMode($value)
- {
- $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
- }
-
- /**
- * @return string the URL to navigate to when a HotSpot object is clicked. Defaults to ''.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * @param string the URL to navigate to when a HotSpot object is clicked.
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string a value that is post back when the HotSpot is clicked. Defaults to ''.
- */
- public function getPostBackValue()
- {
- return $this->getViewState('PostBackValue','');
- }
-
- /**
- * @param string a value that is post back when the HotSpot is clicked.
- */
- public function setPostBackValue($value)
- {
- $this->setViewState('PostBackValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return integer the tab index of the HotSpot region. Defaults to 0.
- */
- public function getTabIndex()
- {
- return $this->getViewState('TabIndex',0);
- }
-
- /**
- * @param integer the tab index of the HotSpot region.
- */
- public function setTabIndex($value)
- {
- $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return boolean whether postback event trigger by this hotspot will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this hotspot will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the hotspot causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the hotspot causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the target window or frame to display the new page when the HotSpot region
- * is clicked. Defaults to ''.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the new page when the HotSpot region
- * is clicked.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return boolean whether the hotspot has custom attributes
- */
- public function getHasAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->getCount()>0;
- else
- return false;
- }
-
- /**
- * Returns the list of custom attributes.
- * Custom attributes are name-value pairs that may be rendered
- * as HTML tags' attributes.
- * @return TAttributeCollection the list of custom attributes
- */
- public function getAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('Attributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->contains($name);
- else
- return false;
- }
-
- /**
- * @return string attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->itemAt($name);
- else
- return null;
- }
-
- /**
- * Sets a custom hotspot attribute.
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, null if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->remove($name);
- else
- return null;
- }
-
- /**
- * Renders this hotspot.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- $writer->addAttribute('shape',$this->getShape());
- $writer->addAttribute('coords',$this->getCoordinates());
- if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=THotSpotMode::Navigate;
- if($mode===THotSpotMode::Navigate)
- {
- $writer->addAttribute('href',$this->getNavigateUrl());
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
- else if($mode===THotSpotMode::Inactive)
- $writer->addAttribute('nohref','true');
- $text=$this->getAlternateText();
- $writer->addAttribute('title',$text);
- $writer->addAttribute('alt',$text);
- if(($accessKey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accessKey);
- if(($tabIndex=$this->getTabIndex())!==0)
- $writer->addAttribute('tabindex',"$tabIndex");
- if($this->getHasAttributes())
- {
- foreach($this->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
- $writer->renderBeginTag('area');
- $writer->renderEndTag();
- }
-}
-
-/**
- * Class TCircleHotSpot.
- *
- * TCircleHotSpot defines a circular hot spot region in a {@link TImageMap}
- * control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCircleHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'circle';
- }
-
- /**
- * @return string coordinates defining this hotspot shape
- */
- public function getCoordinates()
- {
- return $this->getX().','.$this->getY().','.$this->getRadius();
- }
-
- /**
- * @return integer radius of the circular HotSpot region. Defaults to 0.
- */
- public function getRadius()
- {
- return $this->getViewState('Radius',0);
- }
-
- /**
- * @param integer radius of the circular HotSpot region.
- */
- public function setRadius($value)
- {
- $this->setViewState('Radius',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the center of the circular HotSpot region. Defaults to 0.
- */
- public function getX()
- {
- return $this->getViewState('X',0);
- }
-
- /**
- * @param integer the X coordinate of the center of the circular HotSpot region.
- */
- public function setX($value)
- {
- $this->setViewState('X',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the Y coordinate of the center of the circular HotSpot region. Defaults to 0.
- */
- public function getY()
- {
- return $this->getViewState('Y',0);
- }
-
- /**
- * @param integer the Y coordinate of the center of the circular HotSpot region.
- */
- public function setY($value)
- {
- $this->setViewState('Y',TPropertyValue::ensureInteger($value),0);
- }
-}
-
-/**
- * Class TRectangleHotSpot.
- *
- * TRectangleHotSpot defines a rectangle hot spot region in a {@link
- * TImageMap} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRectangleHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'rect';
- }
-
- /**
- * @return string coordinates defining this hotspot shape
- */
- public function getCoordinates()
- {
- return $this->getLeft().','.$this->getTop().','.$this->getRight().','.$this->getBottom();
- }
-
- /**
- * @return integer the Y coordinate of the bottom side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getBottom()
- {
- return $this->getViewState('Bottom',0);
- }
-
- /**
- * @param integer the Y coordinate of the bottom side of the rectangle HotSpot region.
- */
- public function setBottom($value)
- {
- $this->setViewState('Bottom',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getLeft()
- {
- return $this->getViewState('Left',0);
- }
-
- /**
- * @param integer the X coordinate of the right side of the rectangle HotSpot region.
- */
- public function setLeft($value)
- {
- $this->setViewState('Left',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getRight()
- {
- return $this->getViewState('Right',0);
- }
-
- /**
- * @param integer the X coordinate of the right side of the rectangle HotSpot region.
- */
- public function setRight($value)
- {
- $this->setViewState('Right',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the Y coordinate of the top side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getTop()
- {
- return $this->getViewState('Top',0);
- }
-
- /**
- * @param integer the Y coordinate of the top side of the rectangle HotSpot region.
- */
- public function setTop($value)
- {
- $this->setViewState('Top',TPropertyValue::ensureInteger($value),0);
- }
-}
-
-/**
- * Class TPolygonHotSpot.
- *
- * TPolygonHotSpot defines a polygon hot spot region in a {@link
- * TImageMap} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPolygonHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'poly';
- }
-
- /**
- * @return string coordinates of the vertices defining the polygon.
- * Coordinates are concatenated together with comma ','. Each pair
- * represents (x,y) of a vertex.
- */
- public function getCoordinates()
- {
- return $this->getViewState('Coordinates','');
- }
-
- /**
- * @param string coordinates of the vertices defining the polygon.
- * Coordinates are concatenated together with comma ','. Each pair
- * represents (x,y) of a vertex.
- */
- public function setCoordinates($value)
- {
- $this->setViewState('Coordinates',$value,'');
- }
-}
-
-
-/**
- * THotSpotMode class.
- * THotSpotMode defines the enumerable type for the possible hot spot modes.
- *
- * The following enumerable values are defined:
- * - NotSet: the mode is not specified
- * - Navigate: clicking on the hotspot will redirect the browser to a different page
- * - PostBack: clicking on the hotspot will cause a postback
- * - Inactive: the hotspot is inactive (not clickable)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class THotSpotMode extends TEnumerable
-{
- const NotSet='NotSet';
- const Navigate='Navigate';
- const PostBack='PostBack';
- const Inactive='Inactive';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TImage class file + */ +Prado::using('System.Web.UI.WebControls.TImage'); + +/** + * TImageMap class + * + * TImageMap represents an image on a page. Hotspot regions can be defined + * within the image. Depending on the {@link setHotSpotMode HotSpotMode}, + * clicking on the hotspots may trigger a postback or navigate to a specified + * URL. The hotspots defined may be accessed via {@link getHotSpots HotSpots}. + * Each hotspot is described as a {@link THotSpot}, which can be a circle, + * rectangle, polygon, etc. To add hotspot in a template, use the following, + * <code> + * <com:TImageMap> + * <com:TCircleHotSpot ... /> + * <com:TRectangleHotSpot ... /> + * <com:TPolygonHotSpot ... /> + * </com:TImageMap> + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TImageMap extends TImage implements IPostBackEventHandler +{ + const MAP_NAME_PREFIX='ImageMap'; + + /** + * Processes an object that is created during parsing template. + * This method adds {@link THotSpot} objects into the hotspot collection + * of the imagemap. + * @param string|TComponent text string or component parsed and instantiated in template + */ + public function addParsedObject($object) + { + if($object instanceof THotSpot) + $this->getHotSpots()->add($object); + } + + /** + * Adds attribute name-value pairs to renderer. + * This overrides the parent implementation with additional imagemap specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if($this->getHotSpots()->getCount()>0) + { + $writer->addAttribute('usemap','#'.self::MAP_NAME_PREFIX.$this->getClientID()); + $writer->addAttribute('id',$this->getUniqueID()); + } + if($this->getEnabled() && !$this->getEnabled(true)) + $writer->addAttribute('disabled','disabled'); + } + + /** + * Renders this imagemap. + * @param THtmlWriter + */ + public function render($writer) + { + parent::render($writer); + + $hotspots=$this->getHotSpots(); + + if($hotspots->getCount()>0) + { + $clientID=$this->getClientID(); + $cs=$this->getPage()->getClientScript(); + $writer->writeLine(); + $writer->addAttribute('name',self::MAP_NAME_PREFIX.$clientID); + $writer->renderBeginTag('map'); + $writer->writeLine(); + if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet) + $mode=THotSpotMode::Navigate; + $target=$this->getTarget(); + $i=0; + $options['EventTarget'] = $this->getUniqueID(); + $options['StopEvent'] = true; + $cs=$this->getPage()->getClientScript(); + foreach($hotspots as $hotspot) + { + if($hotspot->getHotSpotMode()===THotSpotMode::NotSet) + $hotspot->setHotSpotMode($mode); + if($target!=='' && $hotspot->getTarget()==='') + $hotspot->setTarget($target); + if($hotspot->getHotSpotMode()===THotSpotMode::PostBack) + { + $id=$clientID.'_'.$i; + $writer->addAttribute('id',$id); + $writer->addAttribute('href','#'.$id); //create unique no-op url references + $options['ID']=$id; + $options['EventParameter']="$i"; + $options['CausesValidation']=$hotspot->getCausesValidation(); + $options['ValidationGroup']=$hotspot->getValidationGroup(); + $cs->registerPostBackControl($this->getClientClassName(),$options); + } + $hotspot->render($writer); + $writer->writeLine(); + $i++; + } + $writer->renderEndTag(); + } + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TImageMap'; + } + + /** + * Raises the postback event. + * This method is required by {@link IPostBackEventHandler} interface. + * This method is mainly used by framework and control developers. + * @param TEventParameter the event parameter + */ + public function raisePostBackEvent($param) + { + $postBackValue=null; + if($param!=='') + { + $index=TPropertyValue::ensureInteger($param); + $hotspots=$this->getHotSpots(); + if($index>=0 && $index<$hotspots->getCount()) + { + $hotspot=$hotspots->itemAt($index); + if(($mode=$hotspot->getHotSpotMode())===THotSpotMode::NotSet) + $mode=$this->getHotSpotMode(); + if($mode===THotSpotMode::PostBack) + { + $postBackValue=$hotspot->getPostBackValue(); + if($hotspot->getCausesValidation()) + $this->getPage()->validate($hotspot->getValidationGroup()); + } + } + } + if($postBackValue!==null) + $this->onClick(new TImageMapEventParameter($postBackValue)); + } + + /** + * @return THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. Defaults to THotSpotMode::NotSet. + */ + public function getHotSpotMode() + { + return $this->getViewState('HotSpotMode',THotSpotMode::NotSet); + } + + /** + * Sets the behavior of hotspot regions in this imagemap when they are clicked. + * If an individual hotspot has a mode other than 'NotSet', the mode set in this + * imagemap will be ignored. By default, 'NotSet' is equivalent to 'Navigate'. + * @param THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. + */ + public function setHotSpotMode($value) + { + $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet); + } + + /** + * @return THotSpotCollection collection of hotspots defined in this imagemap. + */ + public function getHotSpots() + { + if(($hotspots=$this->getViewState('HotSpots',null))===null) + { + $hotspots=new THotSpotCollection; + $this->setViewState('HotSpots',$hotspots); + } + return $hotspots; + } + + /** + * @return string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. Defaults to ''. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * @param string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. + */ + public function setTarget($value) + { + $this->setViewState('Target',TPropertyValue::ensureString($value),''); + } + + /** + * Raises <b>OnClick</b> event. + * This method is invoked when a hotspot region is clicked within the imagemap. + * If you override this method, be sure to call the parent implementation + * so that the event handler can be invoked. + * @param TImageMapEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param) + { + $this->raiseEvent('OnClick',$this,$param); + } +} + +/** + * TImageMapEventParameter class. + * + * TImageMapEventParameter represents a postback event parameter + * when a hotspot is clicked and posts back in a {@link TImageMap}. + * To retrieve the post back value associated with the hotspot being clicked, + * access {@link getPostBackValue PostBackValue}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TImageMapEventParameter extends TEventParameter +{ + private $_postBackValue; + + /** + * Constructor. + * @param string post back value associated with the hotspot clicked + */ + public function __construct($postBackValue) + { + $this->_postBackValue=$postBackValue; + } + + /** + * @return string post back value associated with the hotspot clicked + */ + public function getPostBackValue() + { + return $this->_postBackValue; + } +} + +/** + * THotSpotCollection class. + * + * THotSpotCollection represents a collection of hotspots in an imagemap. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class THotSpotCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only {@link THotSpot}. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a THotSpot. + */ + public function insertAt($index,$item) + { + if($item instanceof THotSpot) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('hotspotcollection_hotspot_required'); + } +} + + +/** + * THotSpot class. + * + * THotSpot implements the basic functionality common to all hot spot shapes. + * Derived classes include {@link TCircleHotSpot}, {@link TPolygonHotSpot} + * and {@link TRectangleHotSpot}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class THotSpot extends TComponent +{ + private $_viewState=array(); + + /** + * Returns a viewstate value. + * + * This function is very useful in defining getter functions for component properties + * that must be kept in viewstate. + * @param string the name of the viewstate value to be returned + * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned + * @return mixed the viewstate value corresponding to $key + */ + protected function getViewState($key,$defaultValue=null) + { + return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue; + } + + /** + * Sets a viewstate value. + * + * This function is very useful in defining setter functions for control properties + * that must be kept in viewstate. + * Make sure that the viewstate value must be serializable and unserializable. + * @param string the name of the viewstate value + * @param mixed the viewstate value to be set + * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate. + */ + protected function setViewState($key,$value,$defaultValue=null) + { + if($value===$defaultValue) + unset($this->_viewState[$key]); + else + $this->_viewState[$key]=$value; + } + + /** + * @return string shape of the hotspot, can be 'circle', 'rect', 'poly', etc. + */ + abstract public function getShape(); + /** + * @return string coordinates defining the hotspot shape. + */ + abstract public function getCoordinates(); + + /** + * @return string the access key that allows you to quickly navigate to the HotSpot region. Defaults to ''. + */ + public function getAccessKey() + { + return $this->getViewState('AccessKey',''); + } + + /** + * @param string the access key that allows you to quickly navigate to the HotSpot region. + */ + public function setAccessKey($value) + { + $this->setViewState('AccessKey',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the alternate text to display for a HotSpot object. Defaults to ''. + */ + public function getAlternateText() + { + return $this->getViewState('AlternateText',''); + } + + /** + * @param string the alternate text to display for a HotSpot object. + */ + public function setAlternateText($value) + { + $this->setViewState('AlternateText',TPropertyValue::ensureString($value),''); + } + + /** + * @return THotSpotMode the behavior of a HotSpot object when it is clicked. Defaults to THotSpotMode::NotSet. + */ + public function getHotSpotMode() + { + return $this->getViewState('HotSpotMode',THotSpotMode::NotSet); + } + + /** + * @param THotSpotMode the behavior of a HotSpot object when it is clicked. + */ + public function setHotSpotMode($value) + { + $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet); + } + + /** + * @return string the URL to navigate to when a HotSpot object is clicked. Defaults to ''. + */ + public function getNavigateUrl() + { + return $this->getViewState('NavigateUrl',''); + } + + /** + * @param string the URL to navigate to when a HotSpot object is clicked. + */ + public function setNavigateUrl($value) + { + $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return string a value that is post back when the HotSpot is clicked. Defaults to ''. + */ + public function getPostBackValue() + { + return $this->getViewState('PostBackValue',''); + } + + /** + * @param string a value that is post back when the HotSpot is clicked. + */ + public function setPostBackValue($value) + { + $this->setViewState('PostBackValue',TPropertyValue::ensureString($value),''); + } + + /** + * @return integer the tab index of the HotSpot region. Defaults to 0. + */ + public function getTabIndex() + { + return $this->getViewState('TabIndex',0); + } + + /** + * @param integer the tab index of the HotSpot region. + */ + public function setTabIndex($value) + { + $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return boolean whether postback event trigger by this hotspot will cause input validation, default is true + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this hotspot will cause input validation + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the hotspot causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the hotspot causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return string the target window or frame to display the new page when the HotSpot region + * is clicked. Defaults to ''. + */ + public function getTarget() + { + return $this->getViewState('Target',''); + } + + /** + * @param string the target window or frame to display the new page when the HotSpot region + * is clicked. + */ + public function setTarget($value) + { + $this->setViewState('Target',TPropertyValue::ensureString($value),''); + } + + /** + * @return boolean whether the hotspot has custom attributes + */ + public function getHasAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->getCount()>0; + else + return false; + } + + /** + * Returns the list of custom attributes. + * Custom attributes are name-value pairs that may be rendered + * as HTML tags' attributes. + * @return TAttributeCollection the list of custom attributes + */ + public function getAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes; + else + { + $attributes=new TAttributeCollection; + $this->setViewState('Attributes',$attributes,null); + return $attributes; + } + } + + /** + * @return boolean whether the named attribute exists + */ + public function hasAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->contains($name); + else + return false; + } + + /** + * @return string attribute value, null if attribute does not exist + */ + public function getAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->itemAt($name); + else + return null; + } + + /** + * Sets a custom hotspot attribute. + * @param string attribute name + * @param string value of the attribute + */ + public function setAttribute($name,$value) + { + $this->getAttributes()->add($name,$value); + } + + /** + * Removes the named attribute. + * @param string the name of the attribute to be removed. + * @return string attribute value removed, null if attribute does not exist. + */ + public function removeAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->remove($name); + else + return null; + } + + /** + * Renders this hotspot. + * @param THtmlWriter + */ + public function render($writer) + { + $writer->addAttribute('shape',$this->getShape()); + $writer->addAttribute('coords',$this->getCoordinates()); + if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet) + $mode=THotSpotMode::Navigate; + if($mode===THotSpotMode::Navigate) + { + $writer->addAttribute('href',$this->getNavigateUrl()); + if(($target=$this->getTarget())!=='') + $writer->addAttribute('target',$target); + } + else if($mode===THotSpotMode::Inactive) + $writer->addAttribute('nohref','true'); + $text=$this->getAlternateText(); + $writer->addAttribute('title',$text); + $writer->addAttribute('alt',$text); + if(($accessKey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accessKey); + if(($tabIndex=$this->getTabIndex())!==0) + $writer->addAttribute('tabindex',"$tabIndex"); + if($this->getHasAttributes()) + { + foreach($this->getAttributes() as $name=>$value) + $writer->addAttribute($name,$value); + } + $writer->renderBeginTag('area'); + $writer->renderEndTag(); + } +} + +/** + * Class TCircleHotSpot. + * + * TCircleHotSpot defines a circular hot spot region in a {@link TImageMap} + * control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCircleHotSpot extends THotSpot +{ + /** + * @return string shape of this hotspot. + */ + public function getShape() + { + return 'circle'; + } + + /** + * @return string coordinates defining this hotspot shape + */ + public function getCoordinates() + { + return $this->getX().','.$this->getY().','.$this->getRadius(); + } + + /** + * @return integer radius of the circular HotSpot region. Defaults to 0. + */ + public function getRadius() + { + return $this->getViewState('Radius',0); + } + + /** + * @param integer radius of the circular HotSpot region. + */ + public function setRadius($value) + { + $this->setViewState('Radius',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the X coordinate of the center of the circular HotSpot region. Defaults to 0. + */ + public function getX() + { + return $this->getViewState('X',0); + } + + /** + * @param integer the X coordinate of the center of the circular HotSpot region. + */ + public function setX($value) + { + $this->setViewState('X',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the Y coordinate of the center of the circular HotSpot region. Defaults to 0. + */ + public function getY() + { + return $this->getViewState('Y',0); + } + + /** + * @param integer the Y coordinate of the center of the circular HotSpot region. + */ + public function setY($value) + { + $this->setViewState('Y',TPropertyValue::ensureInteger($value),0); + } +} + +/** + * Class TRectangleHotSpot. + * + * TRectangleHotSpot defines a rectangle hot spot region in a {@link + * TImageMap} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRectangleHotSpot extends THotSpot +{ + /** + * @return string shape of this hotspot. + */ + public function getShape() + { + return 'rect'; + } + + /** + * @return string coordinates defining this hotspot shape + */ + public function getCoordinates() + { + return $this->getLeft().','.$this->getTop().','.$this->getRight().','.$this->getBottom(); + } + + /** + * @return integer the Y coordinate of the bottom side of the rectangle HotSpot region. Defaults to 0. + */ + public function getBottom() + { + return $this->getViewState('Bottom',0); + } + + /** + * @param integer the Y coordinate of the bottom side of the rectangle HotSpot region. + */ + public function setBottom($value) + { + $this->setViewState('Bottom',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0. + */ + public function getLeft() + { + return $this->getViewState('Left',0); + } + + /** + * @param integer the X coordinate of the right side of the rectangle HotSpot region. + */ + public function setLeft($value) + { + $this->setViewState('Left',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0. + */ + public function getRight() + { + return $this->getViewState('Right',0); + } + + /** + * @param integer the X coordinate of the right side of the rectangle HotSpot region. + */ + public function setRight($value) + { + $this->setViewState('Right',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the Y coordinate of the top side of the rectangle HotSpot region. Defaults to 0. + */ + public function getTop() + { + return $this->getViewState('Top',0); + } + + /** + * @param integer the Y coordinate of the top side of the rectangle HotSpot region. + */ + public function setTop($value) + { + $this->setViewState('Top',TPropertyValue::ensureInteger($value),0); + } +} + +/** + * Class TPolygonHotSpot. + * + * TPolygonHotSpot defines a polygon hot spot region in a {@link + * TImageMap} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TPolygonHotSpot extends THotSpot +{ + /** + * @return string shape of this hotspot. + */ + public function getShape() + { + return 'poly'; + } + + /** + * @return string coordinates of the vertices defining the polygon. + * Coordinates are concatenated together with comma ','. Each pair + * represents (x,y) of a vertex. + */ + public function getCoordinates() + { + return $this->getViewState('Coordinates',''); + } + + /** + * @param string coordinates of the vertices defining the polygon. + * Coordinates are concatenated together with comma ','. Each pair + * represents (x,y) of a vertex. + */ + public function setCoordinates($value) + { + $this->setViewState('Coordinates',$value,''); + } +} + + +/** + * THotSpotMode class. + * THotSpotMode defines the enumerable type for the possible hot spot modes. + * + * The following enumerable values are defined: + * - NotSet: the mode is not specified + * - Navigate: clicking on the hotspot will redirect the browser to a different page + * - PostBack: clicking on the hotspot will cause a postback + * - Inactive: the hotspot is inactive (not clickable) + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class THotSpotMode extends TEnumerable +{ + const NotSet='NotSet'; + const Navigate='Navigate'; + const PostBack='PostBack'; + const Inactive='Inactive'; +} + diff --git a/framework/Web/UI/WebControls/TItemDataRenderer.php b/framework/Web/UI/WebControls/TItemDataRenderer.php index 60b34873..80d7f418 100644 --- a/framework/Web/UI/WebControls/TItemDataRenderer.php +++ b/framework/Web/UI/WebControls/TItemDataRenderer.php @@ -1,83 +1,83 @@ -<?php
-/**
- * TItemDataRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TItemDataRenderer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Web.UI.WebControls.TDataRenderer');
-
-/**
- * TItemDataRenderer class
- *
- * TItemDataRenderer is the convient base class for template-based item data renderers.
- * It implements the {@link IItemDataRenderer} interface, and because
- * TItemDataRenderer extends from {@link TTemplateControl}, derived child
- * classes can have templates to define their presentational layout.
- *
- * The following properties are provided by TItemDataRenderer:
- * - {@link getItemIndex ItemIndex}: zero-based index of this renderer in the item list collection.
- * - {@link getItemType ItemType}: item type of this renderer, such as TListItemType::AlternatingItem
- * - {@link getData Data}: data associated with this renderer
-
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-abstract class TItemDataRenderer extends TDataRenderer implements IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of repeater
- */
- private $_itemIndex;
- /**
- * type of the TRepeaterItem
- * @var TListItemType
- */
- private $_itemType;
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ + +Prado::using('System.Web.UI.WebControls.TDataBoundControl'); +Prado::using('System.Web.UI.WebControls.TDataRenderer'); + +/** + * TItemDataRenderer class + * + * TItemDataRenderer is the convient base class for template-based item data renderers. + * It implements the {@link IItemDataRenderer} interface, and because + * TItemDataRenderer extends from {@link TTemplateControl}, derived child + * classes can have templates to define their presentational layout. + * + * The following properties are provided by TItemDataRenderer: + * - {@link getItemIndex ItemIndex}: zero-based index of this renderer in the item list collection. + * - {@link getItemType ItemType}: item type of this renderer, such as TListItemType::AlternatingItem + * - {@link getData Data}: data associated with this renderer + + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.2 + */ +abstract class TItemDataRenderer extends TDataRenderer implements IItemDataRenderer +{ + /** + * index of the data item in the Items collection of repeater + */ + private $_itemIndex; + /** + * type of the TRepeaterItem + * @var TListItemType + */ + private $_itemType; + + /** + * @return TListItemType item type + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type. + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection. + * If the item is not in the collection (e.g. it is a header item), it returns -1. + * @return integer zero-based index of the item. + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value) + { + $this->_itemIndex=TPropertyValue::ensureInteger($value); + } +} + diff --git a/framework/Web/UI/WebControls/TJavascriptLogger.php b/framework/Web/UI/WebControls/TJavascriptLogger.php index e0d695f4..3b430357 100644 --- a/framework/Web/UI/WebControls/TJavascriptLogger.php +++ b/framework/Web/UI/WebControls/TJavascriptLogger.php @@ -1,93 +1,93 @@ -<?php
-/**
- * TJavascriptLogger class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TJavascriptLogger class.
- *
- * Provides logging for client-side javascript. Example: template code
- * <code><com:TJavascriptLogger /></code>
- *
- * Client-side javascript code to log info, error, warn, debug
- * <code>Logger.warn('A warning');
- * Logger.info('something happend');
- * </code>
- *
- * To see the logger and console, press ALT-D (or CTRL-D on OS X).
- * More information on the logger can be found at
- * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
- *
- * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TJavascriptLogger extends TWebControl
-{
- private static $_keyCodes = array(
- '0'=>48, '1'=>49, '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57,
- 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, 'h'=>72,
- 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, 'p'=>80,
- 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, 'x'=>88, 'y'=>89, 'z'=>90);
-
- /**
- * @return string tag name of the panel
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * @param string keyboard key for toggling the console, default is J.
- */
- public function setToggleKey($value)
- {
- $this->setViewState('ToggleKey', $value, 'j');
- }
-
- /**
- * @return string keyboard key for toggling the console.
- */
- public function getToggleKey()
- {
- return $this->getViewState('ToggleKey', 'j');
- }
-
- /**
- * Registers the required logger javascript.
- * @param TEventParameter event parameter
- */
- public function onPreRender($param)
- {
- $key = strtolower($this->getToggleKey());
- $code = isset(self::$_keyCodes[$key]) ? self::$_keyCodes[$key] : 74;
- $js = "var logConsole; Event.OnLoad(function() { logConsole = new LogConsole($code)}); ";
- $cs = $this->getPage()->getClientScript();
- $cs->registerBeginScript($this->getClientID(),$js);
- $cs->registerPradoScript('logger');
- }
-
- /**
- * Register the required javascript libraries and
- * display some general usage information.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- $code = strtoupper($this->getToggleKey());
- $info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
- $link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>';
- $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
- $writer->write("{$usage} {$link} {$info}");
- }
-}
-
+<?php +/** + * TJavascriptLogger class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TJavascriptLogger class. + * + * Provides logging for client-side javascript. Example: template code + * <code><com:TJavascriptLogger /></code> + * + * Client-side javascript code to log info, error, warn, debug + * <code>Logger.warn('A warning'); + * Logger.info('something happend'); + * </code> + * + * To see the logger and console, press ALT-D (or CTRL-D on OS X). + * More information on the logger can be found at + * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/ + * + * @author Wei Zhuo<weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TJavascriptLogger extends TWebControl +{ + private static $_keyCodes = array( + '0'=>48, '1'=>49, '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57, + 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, 'h'=>72, + 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, 'p'=>80, + 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, 'x'=>88, 'y'=>89, 'z'=>90); + + /** + * @return string tag name of the panel + */ + protected function getTagName() + { + return 'div'; + } + + /** + * @param string keyboard key for toggling the console, default is J. + */ + public function setToggleKey($value) + { + $this->setViewState('ToggleKey', $value, 'j'); + } + + /** + * @return string keyboard key for toggling the console. + */ + public function getToggleKey() + { + return $this->getViewState('ToggleKey', 'j'); + } + + /** + * Registers the required logger javascript. + * @param TEventParameter event parameter + */ + public function onPreRender($param) + { + $key = strtolower($this->getToggleKey()); + $code = isset(self::$_keyCodes[$key]) ? self::$_keyCodes[$key] : 74; + $js = "var logConsole; Event.OnLoad(function() { logConsole = new LogConsole($code)}); "; + $cs = $this->getPage()->getClientScript(); + $cs->registerBeginScript($this->getClientID(),$js); + $cs->registerPradoScript('logger'); + } + + /** + * Register the required javascript libraries and + * display some general usage information. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + $code = strtoupper($this->getToggleKey()); + $info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).'; + $link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>'; + $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to'; + $writer->write("{$usage} {$link} {$info}"); + } +} + diff --git a/framework/Web/UI/WebControls/TKeyboard.php b/framework/Web/UI/WebControls/TKeyboard.php index 27cb55c5..58c80e26 100644 --- a/framework/Web/UI/WebControls/TKeyboard.php +++ b/framework/Web/UI/WebControls/TKeyboard.php @@ -1,189 +1,189 @@ -<?php
-/**
- * TKeyboard class file.
- *
- * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-
-/**
- * Class TKeyboard.
- *
- * TKeyboard displays a virtual keyboard that users can click on to enter input in
- * an associated text box. It helps to reduce the keyboard recording hacking.
- *
- * To use TKeyboard, write a template like following:
- * <code>
- * <com:TTextBox ID="PasswordInput" />
- * <com:TKeyboard ForControl="PasswordInput" />
- * </code>
- *
- * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl}
- * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when
- * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to
- * false to keep the keyboard showing all the time.
- *
- * The appearance of the keyboard can also be changed by specifying a customized CSS file via
- * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may
- * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}.
- *
- * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TKeyboard extends TWebControl
-{
- /**
- * @return string the ID path of the {@link TTextBox} control
- */
- public function getForControl()
- {
- return $this->getViewState('ForControl','');
- }
-
- /**
- * Sets the ID path of the {@link TTextBox} control.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the keyboard's naming container to the target control.
- * @param string the ID path
- */
- public function setForControl($value)
- {
- $this->setViewState('ForControl', TPropertyValue::ensureString($value));
- }
-
- /**
- * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true.
- */
- public function getAutoHide()
- {
- return $this->getViewState('AutoHide', true);
- }
-
- /**
- * @param boolean whether the keyboard should be hidden when the textbox is not in focus.
- */
- public function setAutoHide($value)
- {
- $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return string the CSS class name for the keyboard <div> element. Defaults to 'Keyboard'.
- */
- public function getKeyboardCssClass()
- {
- return $this->getViewState('KeyboardCssClass', 'Keyboard');
- }
-
- /**
- * Sets a value indicating the CSS class name for the keyboard <div> element.
- * Note, if you change this property, make sure you also supply a customized CSS file
- * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling.
- * @param string the CSS class name for the keyboard <div> element.
- */
- public function setKeyboardCssClass($value)
- {
- $this->setViewState('KeyboardCssClass', $value, 'Keyboard');
- }
-
- /**
- * @return string the URL for the CSS file to customize the appearance of the keyboard.
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl', '');
- }
-
- /**
- * @param string the URL for the CSS file to customize the appearance of the keyboard.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl', $value, '');
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getPage()->getClientSupportsJavaScript())
- {
- $this->registerStyleSheet();
- $this->registerClientScript();
- }
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional TKeyboard specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if($this->getPage()->getClientSupportsJavaScript())
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * Registers the CSS relevant to the TKeyboard.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- if(($url=$this->getCssUrl())==='')
- $url=$this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'keyboard.css');
- $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $options=TJavaScript::encode($this->getClientOptions());
- $className=$this->getClientClassName();
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('keyboard');
- $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);");
- }
-
- /**
- * @return string the Javascript class name for this control
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TKeyboard';
- }
-
- /**
- * @return array the JavaScript options for this control
- */
- protected function getClientOptions()
- {
- if(($forControl=$this->getForControl())==='')
- throw new TConfigurationException('keyboard_forcontrol_required');
- if(($target=$this->findControl($forControl))===null)
- throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl);
-
- $options['ID'] = $this->getClientID();
- $options['ForControl'] = $target->getClientID();
- $options['AutoHide'] = $this->getAutoHide();
- $options['CssClass'] = $this->getKeyboardCssClass();
-
- return $options;
- }
-}
-
+<?php +/** + * TKeyboard class file. + * + * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * Class TKeyboard. + * + * TKeyboard displays a virtual keyboard that users can click on to enter input in + * an associated text box. It helps to reduce the keyboard recording hacking. + * + * To use TKeyboard, write a template like following: + * <code> + * <com:TTextBox ID="PasswordInput" /> + * <com:TKeyboard ForControl="PasswordInput" /> + * </code> + * + * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl} + * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when + * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to + * false to keep the keyboard showing all the time. + * + * The appearance of the keyboard can also be changed by specifying a customized CSS file via + * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may + * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}. + * + * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TKeyboard extends TWebControl +{ + /** + * @return string the ID path of the {@link TTextBox} control + */ + public function getForControl() + { + return $this->getViewState('ForControl',''); + } + + /** + * Sets the ID path of the {@link TTextBox} control. + * The ID path is the dot-connected IDs of the controls reaching from + * the keyboard's naming container to the target control. + * @param string the ID path + */ + public function setForControl($value) + { + $this->setViewState('ForControl', TPropertyValue::ensureString($value)); + } + + /** + * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true. + */ + public function getAutoHide() + { + return $this->getViewState('AutoHide', true); + } + + /** + * @param boolean whether the keyboard should be hidden when the textbox is not in focus. + */ + public function setAutoHide($value) + { + $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return string the CSS class name for the keyboard <div> element. Defaults to 'Keyboard'. + */ + public function getKeyboardCssClass() + { + return $this->getViewState('KeyboardCssClass', 'Keyboard'); + } + + /** + * Sets a value indicating the CSS class name for the keyboard <div> element. + * Note, if you change this property, make sure you also supply a customized CSS file + * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling. + * @param string the CSS class name for the keyboard <div> element. + */ + public function setKeyboardCssClass($value) + { + $this->setViewState('KeyboardCssClass', $value, 'Keyboard'); + } + + /** + * @return string the URL for the CSS file to customize the appearance of the keyboard. + */ + public function getCssUrl() + { + return $this->getViewState('CssUrl', ''); + } + + /** + * @param string the URL for the CSS file to customize the appearance of the keyboard. + */ + public function setCssUrl($value) + { + $this->setViewState('CssUrl', $value, ''); + } + + /** + * Registers CSS and JS. + * This method is invoked right before the control rendering, if the control is visible. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getPage()->getClientSupportsJavaScript()) + { + $this->registerStyleSheet(); + $this->registerClientScript(); + } + } + + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation with additional TKeyboard specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if($this->getPage()->getClientSupportsJavaScript()) + $writer->addAttribute('id',$this->getClientID()); + } + + /** + * Registers the CSS relevant to the TKeyboard. + * It will register the CSS file specified by {@link getCssUrl CssUrl}. + * If that is not set, it will use the default CSS. + */ + protected function registerStyleSheet() + { + if(($url=$this->getCssUrl())==='') + $url=$this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'keyboard.css'); + $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url); + } + + /** + * Registers the relevant JavaScript. + */ + protected function registerClientScript() + { + $options=TJavaScript::encode($this->getClientOptions()); + $className=$this->getClientClassName(); + $cs=$this->getPage()->getClientScript(); + $cs->registerPradoScript('keyboard'); + $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);"); + } + + /** + * @return string the Javascript class name for this control + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TKeyboard'; + } + + /** + * @return array the JavaScript options for this control + */ + protected function getClientOptions() + { + if(($forControl=$this->getForControl())==='') + throw new TConfigurationException('keyboard_forcontrol_required'); + if(($target=$this->findControl($forControl))===null) + throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl); + + $options['ID'] = $this->getClientID(); + $options['ForControl'] = $target->getClientID(); + $options['AutoHide'] = $this->getAutoHide(); + $options['CssClass'] = $this->getKeyboardCssClass(); + + return $options; + } +} + diff --git a/framework/Web/UI/WebControls/TLabel.php b/framework/Web/UI/WebControls/TLabel.php index 31e424e5..7228d588 100644 --- a/framework/Web/UI/WebControls/TLabel.php +++ b/framework/Web/UI/WebControls/TLabel.php @@ -1,154 +1,154 @@ -<?php
-/**
- * TLabel class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TLabel class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLabel class
- *
- * TLabel displays a piece of text on a Web page.
- * Use {@link setText Text} property to set the text to be displayed.
- * TLabel will render the contents enclosed within its component tag
- * if {@link setText Text} is empty.
- * To use TLabel as a form label, associate it with a control by setting the
- * {@link setForControl ForControl} property.
- * The associated control must be locatable within the label's naming container.
- * If the associated control is not visible, the label will not be rendered, either.
- *
- * Note, {@link setText Text} will NOT be encoded for rendering.
- * Make sure it does not contain dangerous characters that you want to avoid.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLabel extends TWebControl implements IDataRenderer
-{
- private $_forControl='';
-
- /**
- * @return string tag name of the label, returns 'label' if there is an associated control, 'span' otherwise.
- */
- protected function getTagName()
- {
- return ($this->getForControl()==='')?'span':'label';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- * @throws TInvalidDataValueException if associated control cannot be found using the ID
- */
- protected function addAttributesToRender($writer)
- {
- if($this->_forControl!=='')
- $writer->addAttribute('for',$this->_forControl);
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the label.
- * It overrides the parent implementation by checking if an associated
- * control is visible or not. If not, the label will not be rendered.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if(($aid=$this->getForControl())!=='')
- {
- if($control=$this->findControl($aid))
- {
- if($control->getVisible(true))
- {
- $this->_forControl=$control->getClientID();
- parent::render($writer);
- }
- }
- else
- throw new TInvalidDataValueException('label_associatedcontrol_invalid',$aid);
- }
- else
- parent::render($writer);
- }
-
- /**
- * Renders the body content of the label.
- * @param THtmlWriter the renderer
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string the text value of the label
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string the text value of the label
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the text value of the label.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text value of the label
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text value of the label.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text value of the label
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the associated control ID
- */
- public function getForControl()
- {
- return $this->getViewState('ForControl','');
- }
-
- /**
- * Sets the ID of the control that the label is associated with.
- * The control must be locatable via {@link TControl::findControl} using the ID.
- * @param string the associated control ID
- */
- public function setForControl($value)
- {
- $this->setViewState('ForControl',$value,'');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TLabel class + * + * TLabel displays a piece of text on a Web page. + * Use {@link setText Text} property to set the text to be displayed. + * TLabel will render the contents enclosed within its component tag + * if {@link setText Text} is empty. + * To use TLabel as a form label, associate it with a control by setting the + * {@link setForControl ForControl} property. + * The associated control must be locatable within the label's naming container. + * If the associated control is not visible, the label will not be rendered, either. + * + * Note, {@link setText Text} will NOT be encoded for rendering. + * Make sure it does not contain dangerous characters that you want to avoid. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TLabel extends TWebControl implements IDataRenderer +{ + private $_forControl=''; + + /** + * @return string tag name of the label, returns 'label' if there is an associated control, 'span' otherwise. + */ + protected function getTagName() + { + return ($this->getForControl()==='')?'span':'label'; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + * @throws TInvalidDataValueException if associated control cannot be found using the ID + */ + protected function addAttributesToRender($writer) + { + if($this->_forControl!=='') + $writer->addAttribute('for',$this->_forControl); + parent::addAttributesToRender($writer); + } + + /** + * Renders the label. + * It overrides the parent implementation by checking if an associated + * control is visible or not. If not, the label will not be rendered. + * @param THtmlWriter writer + */ + public function render($writer) + { + if(($aid=$this->getForControl())!=='') + { + if($control=$this->findControl($aid)) + { + if($control->getVisible(true)) + { + $this->_forControl=$control->getClientID(); + parent::render($writer); + } + } + else + throw new TInvalidDataValueException('label_associatedcontrol_invalid',$aid); + } + else + parent::render($writer); + } + + /** + * Renders the body content of the label. + * @param THtmlWriter the renderer + */ + public function renderContents($writer) + { + if(($text=$this->getText())==='') + parent::renderContents($writer); + else + $writer->write($text); + } + + /** + * @return string the text value of the label + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * @param string the text value of the label + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the text value of the label. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text value of the label + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the text value of the label. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text value of the label + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return string the associated control ID + */ + public function getForControl() + { + return $this->getViewState('ForControl',''); + } + + /** + * Sets the ID of the control that the label is associated with. + * The control must be locatable via {@link TControl::findControl} using the ID. + * @param string the associated control ID + */ + public function setForControl($value) + { + $this->setViewState('ForControl',$value,''); + } +} + diff --git a/framework/Web/UI/WebControls/TLinkButton.php b/framework/Web/UI/WebControls/TLinkButton.php index 9da5ec59..f03f9098 100644 --- a/framework/Web/UI/WebControls/TLinkButton.php +++ b/framework/Web/UI/WebControls/TLinkButton.php @@ -1,334 +1,334 @@ -<?php
-/**
- * TLinkButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TLinkButton class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLinkButton class
- *
- * TLinkButton creates a hyperlink style button on the page.
- * TLinkButton has the same appearance as a hyperlink. However, it is mainly
- * used to submit data to a page. Like {@link TButton}, you can create either
- * a <b>submit</b> button or a <b>command</b> button.
- *
- * A <b>command</b> button has a command name (specified by
- * the {@link setCommandName CommandName} property) and and a command parameter
- * (specified by {@link setCommandParameter CommandParameter} property)
- * associated with the button. This allows you to create multiple TLinkButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter. You can provide an event handler for
- * {@link onCommand OnCommand} event to programmatically control the actions performed
- * when the command button is clicked. In the event handler, you can determine
- * the {@link setCommandName CommandName} property value and
- * the {@link setCommandParameter CommandParameter} property value
- * through the {@link TCommandParameter::getName Name} and
- * {@link TCommandParameter::getParameter Parameter} properties of the event
- * parameter which is of type {@link TCommandEventParameter}.
- *
- * A <b>submit</b> button does not have a command name associated with the button
- * and clicking on it simply posts the Web page back to the server.
- * By default, a TLinkButton component is a submit button.
- * You can provide an event handler for the {@link onClick OnClick} event
- * to programmatically control the actions performed when the submit button is clicked.
- *
- * Clicking on button can trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * And the validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TLinkButton will display the {@link setText Text} property value
- * as the hyperlink text. If {@link setText Text} is empty, the body content
- * of TLinkButton will be displayed. Therefore, you can use TLinkButton
- * as an image button by enclosing an <img> tag as the body of TLinkButton.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLinkButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
-{
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'a';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
-
- $writer->addAttribute('id',$this->getClientID());
-
- // We call parent implementation here because some attributes
- // may be overwritten in the following
- parent::addAttributesToRender($writer);
-
- if($this->getEnabled(true) && $this->getEnableClientScript())
- {
- $this->renderLinkButtonHref($writer);
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Renders the client-script code.
- * @param THtmlWriter renderer
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * Renders the Href for link button.
- * @param THtmlWriter renderer
- */
- protected function renderLinkButtonHref($writer)
- {
- //create unique no-op url references
- $nop = "javascript:;//".$this->getClientID();
- $writer->addAttribute('href', $nop);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TLinkButton';
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['StopEvent'] = true;
-
- return $options;
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * If {@link getText Text} is not empty, it will be rendered. Otherwise,
- * the body content enclosed in the control tag will be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string the text caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string caption of the button.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string caption of the button
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * Sets the value indicating whether postback event trigger by this button will cause input validation.
- * @param string the text caption to be set
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(null);
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TLinkButton class + * + * TLinkButton creates a hyperlink style button on the page. + * TLinkButton has the same appearance as a hyperlink. However, it is mainly + * used to submit data to a page. Like {@link TButton}, you can create either + * a <b>submit</b> button or a <b>command</b> button. + * + * A <b>command</b> button has a command name (specified by + * the {@link setCommandName CommandName} property) and and a command parameter + * (specified by {@link setCommandParameter CommandParameter} property) + * associated with the button. This allows you to create multiple TLinkButton + * components on a Web page and programmatically determine which one is clicked + * with what parameter. You can provide an event handler for + * {@link onCommand OnCommand} event to programmatically control the actions performed + * when the command button is clicked. In the event handler, you can determine + * the {@link setCommandName CommandName} property value and + * the {@link setCommandParameter CommandParameter} property value + * through the {@link TCommandParameter::getName Name} and + * {@link TCommandParameter::getParameter Parameter} properties of the event + * parameter which is of type {@link TCommandEventParameter}. + * + * A <b>submit</b> button does not have a command name associated with the button + * and clicking on it simply posts the Web page back to the server. + * By default, a TLinkButton component is a submit button. + * You can provide an event handler for the {@link onClick OnClick} event + * to programmatically control the actions performed when the submit button is clicked. + * + * Clicking on button can trigger form validation, if + * {@link setCausesValidation CausesValidation} is true. + * And the validation may be restricted within a certain group of validator + * controls by setting {@link setValidationGroup ValidationGroup} property. + * If validation is successful, the data will be post back to the same page. + * + * TLinkButton will display the {@link setText Text} property value + * as the hyperlink text. If {@link setText Text} is empty, the body content + * of TLinkButton will be displayed. Therefore, you can use TLinkButton + * as an image button by enclosing an <img> tag as the body of TLinkButton. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TLinkButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer +{ + /** + * @return string tag name of the button + */ + protected function getTagName() + { + return 'a'; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Adds attribute name-value pairs to renderer. + * This overrides the parent implementation with additional button specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $page=$this->getPage(); + $page->ensureRenderInForm($this); + + $writer->addAttribute('id',$this->getClientID()); + + // We call parent implementation here because some attributes + // may be overwritten in the following + parent::addAttributesToRender($writer); + + if($this->getEnabled(true) && $this->getEnableClientScript()) + { + $this->renderLinkButtonHref($writer); + $this->renderClientControlScript($writer); + } + else if($this->getEnabled()) // in this case, parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + } + + /** + * Renders the client-script code. + * @param THtmlWriter renderer + */ + protected function renderClientControlScript($writer) + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * @param boolean set by a panel to register this button as the default button for the panel. + */ + public function setIsDefaultButton($value) + { + $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean true if this button is registered as a default button for a panel. + */ + public function getIsDefaultButton() + { + return $this->getViewState('IsDefaultButton', false); + } + + /** + * Renders the Href for link button. + * @param THtmlWriter renderer + */ + protected function renderLinkButtonHref($writer) + { + //create unique no-op url references + $nop = "javascript:;//".$this->getClientID(); + $writer->addAttribute('href', $nop); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TLinkButton'; + } + + /** + * Returns postback specifications for the button. + * This method is used by framework and control developers. + * @return array parameters about how the button defines its postback behavior. + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['StopEvent'] = true; + + return $options; + } + + /** + * Renders the body content enclosed between the control tag. + * If {@link getText Text} is not empty, it will be rendered. Otherwise, + * the body content enclosed in the control tag will be rendered. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderContents($writer) + { + if(($text=$this->getText())==='') + parent::renderContents($writer); + else + $writer->write($text); + } + + /** + * @return string the text caption of the button + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * @param string the text caption to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the caption of the button. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string caption of the button. + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the caption of the button. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string caption of the button + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return string the command name associated with the {@link onCommand OnCommand} event. + */ + public function getCommandName() + { + return $this->getViewState('CommandName',''); + } + + /** + * @param string the command name associated with the {@link onCommand OnCommand} event. + */ + public function setCommandName($value) + { + $this->setViewState('CommandName',$value,''); + } + + /** + * @return string the parameter associated with the {@link onCommand OnCommand} event + */ + public function getCommandParameter() + { + return $this->getViewState('CommandParameter',''); + } + + /** + * @param string the parameter associated with the {@link onCommand OnCommand} event. + */ + public function setCommandParameter($value) + { + $this->setViewState('CommandParameter',$value,''); + } + + /** + * @return boolean whether postback event trigger by this button will cause input validation + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * Sets the value indicating whether postback event trigger by this button will cause input validation. + * @param string the text caption to be set + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the group of validators which the button causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the button causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * Raises the postback event. + * This method is required by {@link IPostBackEventHandler} interface. + * If {@link getCausesValidation CausesValidation} is true, it will + * invoke the page's {@link TPage::validate validate} method first. + * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events. + * This method is mainly used by framework and control developers. + * @param TEventParameter the event parameter + */ + public function raisePostBackEvent($param) + { + if($this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onClick(null); + $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter())); + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnClick' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handler can be invoked. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onClick($param) + { + $this->raiseEvent('OnClick',$this,$param); + } + + /** + * This method is invoked when the button is clicked. + * The method raises 'OnCommand' event to fire up the event handlers. + * If you override this method, be sure to call the parent implementation + * so that the event handlers can be invoked. + * @param TCommandEventParameter event parameter to be passed to the event handlers + */ + public function onCommand($param) + { + $this->raiseEvent('OnCommand',$this,$param); + $this->raiseBubbleEvent($this,$param); + } +} + diff --git a/framework/Web/UI/WebControls/TListBox.php b/framework/Web/UI/WebControls/TListBox.php index 8e996b6e..f7ab4791 100644 --- a/framework/Web/UI/WebControls/TListBox.php +++ b/framework/Web/UI/WebControls/TListBox.php @@ -1,226 +1,226 @@ -<?php
-/**
- * TListBox class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TListBox class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TListBox class
- *
- * TListBox displays a list box on a Web page that allows single or multiple selection.
- * The list box allows multiple selections if {@link setSelectionMode SelectionMode}
- * is TListSelectionMode::Multiple. It takes single selection only if Single.
- * The property {@link setRows Rows} specifies how many rows of options are visible
- * at a time. See {@link TListControl} for inherited properties.
- *
- * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for
- * a list item, set a Group attribute with it,
- * <code>
- * $listitem->Attributes->Group="Group Name";
- * // or <com:TListItem Attributes.Group="Group Name" .../> in template
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListBox extends TListControl implements IPostBackDataHandler, IValidatable
-{
- private $_dataChanged=false;
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TListControl class + */ +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * TListBox class + * + * TListBox displays a list box on a Web page that allows single or multiple selection. + * The list box allows multiple selections if {@link setSelectionMode SelectionMode} + * is TListSelectionMode::Multiple. It takes single selection only if Single. + * The property {@link setRows Rows} specifies how many rows of options are visible + * at a time. See {@link TListControl} for inherited properties. + * + * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for + * a list item, set a Group attribute with it, + * <code> + * $listitem->Attributes->Group="Group Name"; + * // or <com:TListItem Attributes.Group="Group Name" .../> in template + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TListBox extends TListControl implements IPostBackDataHandler, IValidatable +{ + private $_dataChanged=false; private $_isValid=true; -
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional list box specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $rows=$this->getRows();
- $writer->addAttribute('size',"$rows");
- if($this->getSelectionMode()===TListSelectionMode::Multiple)
- $writer->addAttribute('name',$this->getUniqueID().'[]');
- else
- $writer->addAttribute('name',$this->getUniqueID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListBox';
- }
-
- /**
- * Registers the list control to load post data on postback.
- * This method overrides the parent implementation.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if(!$this->getEnabled(true))
- return false;
- $this->ensureDataBound();
- $selections=isset($values[$key])?$values[$key]:null;
- if($selections!==null)
- {
- $items=$this->getItems();
- if($this->getSelectionMode()===TListSelectionMode::Single)
- {
- $selection=is_array($selections)?$selections[0]:$selections;
- $index=$items->findIndexByValue($selection,false);
- if($this->getSelectedIndex()!==$index)
- {
- $this->setSelectedIndex($index);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
- if(!is_array($selections))
- $selections=array($selections);
- $list=array();
- foreach($selections as $selection)
- $list[]=$items->findIndexByValue($selection,false);
- $list2=$this->getSelectedIndices();
- $n=count($list);
- $flag=false;
- if($n===count($list2))
- {
- sort($list,SORT_NUMERIC);
- for($i=0;$i<$n;++$i)
- {
- if($list[$i]!==$list2[$i])
- {
- $flag=true;
- break;
- }
- }
- }
- else
- $flag=true;
- if($flag)
- {
- $this->setSelectedIndices($list);
- $this->_dataChanged=true;
- }
- return $flag;
- }
- else if($this->getSelectedIndex()!==-1)
- {
- $this->clearSelection();
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @return boolean whether this control allows multiple selection
- */
- protected function getIsMultiSelect()
- {
- return $this->getSelectionMode()===TListSelectionMode::Multiple;
- }
-
- /**
- * @return integer the number of rows to be displayed in the list control
- */
- public function getRows()
- {
- return $this->getViewState('Rows', 4);
- }
-
- /**
- * @param integer the number of rows to be displayed in the list control
- */
- public function setRows($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value<=0)
- $value=4;
- $this->setViewState('Rows', $value, 4);
- }
-
- /**
- * @return TListSelectionMode the selection mode (Single, Multiple). Defaults to TListSelectionMode::Single.
- */
- public function getSelectionMode()
- {
- return $this->getViewState('SelectionMode', TListSelectionMode::Single);
- }
-
- /**
- * @param TListSelectionMode the selection mode
- */
- public function setSelectionMode($value)
- {
- $this->setViewState('SelectionMode',TPropertyValue::ensureEnum($value,'TListSelectionMode'),TListSelectionMode::Single);
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
+ + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation with additional list box specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $rows=$this->getRows(); + $writer->addAttribute('size',"$rows"); + if($this->getSelectionMode()===TListSelectionMode::Multiple) + $writer->addAttribute('name',$this->getUniqueID().'[]'); + else + $writer->addAttribute('name',$this->getUniqueID()); + parent::addAttributesToRender($writer); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TListBox'; + } + + /** + * Registers the list control to load post data on postback. + * This method overrides the parent implementation. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getEnabled(true)) + $this->getPage()->registerRequiresPostData($this); + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + if(!$this->getEnabled(true)) + return false; + $this->ensureDataBound(); + $selections=isset($values[$key])?$values[$key]:null; + if($selections!==null) + { + $items=$this->getItems(); + if($this->getSelectionMode()===TListSelectionMode::Single) + { + $selection=is_array($selections)?$selections[0]:$selections; + $index=$items->findIndexByValue($selection,false); + if($this->getSelectedIndex()!==$index) + { + $this->setSelectedIndex($index); + return $this->_dataChanged=true; + } + else + return false; + } + if(!is_array($selections)) + $selections=array($selections); + $list=array(); + foreach($selections as $selection) + $list[]=$items->findIndexByValue($selection,false); + $list2=$this->getSelectedIndices(); + $n=count($list); + $flag=false; + if($n===count($list2)) + { + sort($list,SORT_NUMERIC); + for($i=0;$i<$n;++$i) + { + if($list[$i]!==$list2[$i]) + { + $flag=true; + break; + } + } + } + else + $flag=true; + if($flag) + { + $this->setSelectedIndices($list); + $this->_dataChanged=true; + } + return $flag; + } + else if($this->getSelectedIndex()!==-1) + { + $this->clearSelection(); + return $this->_dataChanged=true; + } + else + return false; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onSelectedIndexChanged(null); + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * @return boolean whether this control allows multiple selection + */ + protected function getIsMultiSelect() + { + return $this->getSelectionMode()===TListSelectionMode::Multiple; + } + + /** + * @return integer the number of rows to be displayed in the list control + */ + public function getRows() + { + return $this->getViewState('Rows', 4); + } + + /** + * @param integer the number of rows to be displayed in the list control + */ + public function setRows($value) + { + $value=TPropertyValue::ensureInteger($value); + if($value<=0) + $value=4; + $this->setViewState('Rows', $value, 4); + } + + /** + * @return TListSelectionMode the selection mode (Single, Multiple). Defaults to TListSelectionMode::Single. + */ + public function getSelectionMode() + { + return $this->getViewState('SelectionMode', TListSelectionMode::Single); + } + + /** + * @param TListSelectionMode the selection mode + */ + public function setSelectionMode($value) + { + $this->setViewState('SelectionMode',TPropertyValue::ensureEnum($value,'TListSelectionMode'),TListSelectionMode::Single); + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getSelectedValue(); + } /** * Returns true if this control validated successfully. @@ -238,25 +238,25 @@ class TListBox extends TListControl implements IPostBackDataHandler, IValidatabl { $this->_isValid=TPropertyValue::ensureBoolean($value); } -}
-
-
-/**
- * TListSelectionMode class.
- * TListSelectionMode defines the enumerable type for the possible selection modes of a {@link TListBox}.
- *
- * The following enumerable values are defined:
- * - Single: single selection
- * - Multiple: allow multiple selection
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TListSelectionMode extends TEnumerable
-{
- const Single='Single';
- const Multiple='Multiple';
-}
-
+} + + +/** + * TListSelectionMode class. + * TListSelectionMode defines the enumerable type for the possible selection modes of a {@link TListBox}. + * + * The following enumerable values are defined: + * - Single: single selection + * - Multiple: allow multiple selection + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TListSelectionMode extends TEnumerable +{ + const Single='Single'; + const Multiple='Multiple'; +} + diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php index 1a07a292..4d388d45 100644 --- a/framework/Web/UI/WebControls/TListControl.php +++ b/framework/Web/UI/WebControls/TListControl.php @@ -1,923 +1,923 @@ -<?php
-
-/**
- * TListControl class file
- *
- * @author Robin J. Rogge <rojaro@gmail.com>
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes the supporting classes
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Web.UI.WebControls.TListItem');
-Prado::using('System.Collections.TListItemCollection');
-Prado::using('System.Collections.TAttributeCollection');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TListControl class
- *
- * TListControl is a base class for list controls, such as {@link TListBox},
- * {@link TDropDownList}, {@link TCheckBoxList}, etc.
- * It manages the items and their status in a list control.
- * It also implements how the items can be populated from template and
- * data source.
- *
- * The property {@link getItems} returns a list of the items in the control.
- * To specify or determine which item is selected, use the
- * {@link getSelectedIndex SelectedIndex} property that indicates the zero-based
- * index of the selected item in the item list. You may also use
- * {@link getSelectedItem SelectedItem} and {@link getSelectedValue SelectedValue}
- * to get the selected item and its value. For multiple selection lists
- * (such as {@link TCheckBoxList} and {@link TListBox}), property
- * {@link getSelectedIndices SelectedIndices} is useful.
- *
- * TListControl implements {@link setAutoPostBack AutoPostBack} which allows
- * a list control to postback the page if the selections of the list items are changed.
- * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
- * properties may be used to specify that validation be performed when auto postback occurs.
- *
- * There are three ways to populate the items in a list control: from template,
- * using {@link setDataSource DataSource} and using {@link setDataSourceID DataSourceID}.
- * The latter two are covered in {@link TDataBoundControl}. To specify items via
- * template, using the following template syntax:
- * <code>
- * <com:TListControl>
- * <com:TListItem Value="xxx" Text="yyy" >
- * <com:TListItem Value="xxx" Text="yyy" Selected="true" >
- * <com:TListItem Value="xxx" Text="yyy" >
- * </com:TListControl>
- * </code>
- *
- * When {@link setDataSource DataSource} or {@link setDataSourceID DataSourceID}
- * is used to populate list items, the {@link setDataTextField DataTextField} and
- * {@link setDataValueField DataValueField} properties are used to specify which
- * columns of the data will be used to populate the text and value of the items.
- * For example, if a data source is as follows,
- * <code>
- * $dataSource=array(
- * array('name'=>'John', 'age'=>31),
- * array('name'=>'Cary', 'age'=>28),
- * array('name'=>'Rose', 'age'=>35),
- * );
- * </code>
- * setting {@link setDataTextField DataTextField} and {@link setDataValueField DataValueField}
- * to 'name' and 'age' will make the first item's text be 'John', value be 31,
- * the second item's text be 'Cary', value be 28, and so on.
- * The {@link setDataTextFormatString DataTextFormatString} property may be further
- * used to format how the item should be displayed. See {@link formatDataValue()}
- * for an explanation of the format string.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TListControl extends TDataBoundControl implements IDataRenderer
-{
- /**
- * @var TListItemCollection item list
- */
- private $_items=null;
- /**
- * @var boolean whether items are restored from viewstate
- */
- private $_stateLoaded=false;
- /**
- * @var mixed the following selection variables are used
- * to keep selections when Items are not available
- */
- private $_cachedSelectedIndex=-1;
- private $_cachedSelectedValue=null;
- private $_cachedSelectedIndices=null;
- private $_cachedSelectedValues=null;
-
- /**
- * @return string tag name of the list control
- */
- protected function getTagName()
- {
- return 'select';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- if($this->getIsMultiSelect())
- $writer->addAttribute('multiple','multiple');
- if($this->getEnabled(true))
- {
- if($this->getAutoPostBack()
- && $this->getEnableClientScript()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- }
- else if($this->getEnabled())
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the javascript for list control.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * Derived classes may override this method and return customized js class names.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListControl';
- }
-
- /**
- * @return array postback options for JS postback code
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- // Do not add items from template if items are loaded from viewstate
- if(!$this->_stateLoaded && ($object instanceof TListItem))
- {
- $index=$this->getItems()->add($object);
- if(($this->_cachedSelectedValue!==null && $this->_cachedSelectedValue===$object->getValue()) || ($this->_cachedSelectedIndex===$index))
- {
- $object->setSelected(true);
- $this->_cachedSelectedValue=null;
- $this->_cachedSelectedIndex=-1;
- }
- }
- }
-
- /**
- * Performs databinding to populate list items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $items=$this->getItems();
- if(!$this->getAppendDataBoundItems())
- $items->clear();
- $textField=$this->getDataTextField();
- if($textField==='')
- $textField=0;
- $valueField=$this->getDataValueField();
- if($valueField==='')
- $valueField=1;
- $textFormat=$this->getDataTextFormatString();
- $groupField=$this->getDataGroupField();
- foreach($data as $key=>$object)
- {
- $item=$items->createListItem();
- if(is_array($object) || is_object($object))
- {
- $text=TDataFieldAccessor::getDataFieldValue($object,$textField);
- $value=TDataFieldAccessor::getDataFieldValue($object,$valueField);
- $item->setValue($value);
- if($groupField!=='')
- $item->setAttribute('Group',TDataFieldAccessor::getDataFieldValue($object,$groupField));
- }
- else
- {
- $text=$object;
- $item->setValue("$key");
- }
- $item->setText($this->formatDataValue($textFormat,$text));
- }
- // SelectedValue or SelectedIndex may be set before databinding
- // so we make them be effective now
- if($this->_cachedSelectedValue!==null)
- {
- $this->setSelectedValue($this->_cachedSelectedValue);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedIndex!==-1)
- {
- $this->setSelectedIndex($this->_cachedSelectedIndex);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedValues!==null)
- {
- $this->setSelectedValues($this->_cachedSelectedValues);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedIndices!==null)
- {
- $this->setSelectedIndices($this->_cachedSelectedIndices);
- $this->resetCachedSelections();
- }
- }
-
- private function resetCachedSelections()
- {
- $this->_cachedSelectedValue=null;
- $this->_cachedSelectedIndex=-1;
- $this->_cachedSelectedValues=null;
- $this->_cachedSelectedIndices=null;
- }
-
- /**
- * Creates a collection object to hold list items.
- * This method may be overriden to create a customized collection.
- * @return TListItemCollection the collection object
- */
- protected function createListItemCollection()
- {
- return new TListItemCollection;
- }
-
- /**
- * Saves items into viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('Items',$this->_items->saveState(),null);
- else
- $this->clearViewState('Items');
- }
-
- /**
- * Loads items from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- $this->_stateLoaded=true;
- if(!$this->getIsDataBound())
- {
- $this->_items=$this->createListItemCollection();
- $this->_items->loadState($this->getViewState('Items',null));
- }
- $this->clearViewState('Items');
- }
-
- /**
- * @return boolean whether this is a multiselect control. Defaults to false.
- */
- protected function getIsMultiSelect()
- {
- return false;
- }
-
- /**
- * @return boolean whether performing databind should append items or clear the existing ones. Defaults to false.
- */
- public function getAppendDataBoundItems()
- {
- return $this->getViewState('AppendDataBoundItems',false);
- }
-
- /**
- * @param boolean whether performing databind should append items or clear the existing ones.
- */
- public function setAppendDataBoundItems($value)
- {
- $this->setViewState('AppendDataBoundItems',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user makes change to the list control and then tabs out of it.
- * Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * makes change to the list control and then tabs out of it.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event trigger by this list control will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this list control will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the field of the data source that provides the text content of the list items.
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field of the data source that provides the text content of the list items.
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how data bound to the list control is displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * Sets data text format string.
- * The format string is used in {@link TDataValueFormatter::format()} to format the Text property value
- * of each item in the list control.
- * @param string the formatting string used to control how data bound to the list control is displayed.
- * @see TDataValueFormatter::format()
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the value of each list item.
- */
- public function getDataValueField()
- {
- return $this->getViewState('DataValueField','');
- }
-
- /**
- * @param string the field of the data source that provides the value of each list item.
- */
- public function setDataValueField($value)
- {
- $this->setViewState('DataValueField',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the label of the list item groups
- */
- public function getDataGroupField()
- {
- return $this->getViewState('DataGroupField','');
- }
-
- /**
- * @param string the field of the data source that provides the label of the list item groups
- */
- public function setDataGroupField($value)
- {
- $this->setViewState('DataGroupField',$value,'');
- }
-
- /**
- * @return integer the number of items in the list control
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * @return boolean whether the list control contains any items.
- */
- public function getHasItems()
- {
- return ($this->_items && $this->_items->getCount()>0);
- }
-
- /**
- * @return TListItemCollection the item collection
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=$this->createListItemCollection();
- return $this->_items;
- }
-
- /**
- * @return integer the index (zero-based) of the item being selected, -1 if no item is selected.
- */
- public function getSelectedIndex()
- {
- if($this->_items)
- {
- $n=$this->_items->getCount();
- for($i=0;$i<$n;++$i)
- if($this->_items->itemAt($i)->getSelected())
- return $i;
- }
- return -1;
- }
-
- /**
- * @param integer the index (zero-based) of the item to be selected
- */
- public function setSelectedIndex($index)
- {
- if(($index=TPropertyValue::ensureInteger($index))<0)
- $index=-1;
- if($this->_items)
- {
- $this->clearSelection();
- if($index>=0 && $index<$this->_items->getCount())
- $this->_items->itemAt($index)->setSelected(true);
- }
- $this->_cachedSelectedIndex=$index;
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedIndex($index);
- }
-
- /**
- * @return array list of index of items that are selected
- */
- public function getSelectedIndices()
- {
- $selections=array();
- if($this->_items)
- {
- $n=$this->_items->getCount();
- for($i=0;$i<$n;++$i)
- if($this->_items->itemAt($i)->getSelected())
- $selections[]=$i;
- }
- return $selections;
- }
-
- /**
- * @param array list of index of items to be selected
- */
- public function setSelectedIndices($indices)
- {
- if($this->getIsMultiSelect())
- {
- if($this->_items)
- {
- $this->clearSelection();
- $n=$this->_items->getCount();
- foreach($indices as $index)
- {
- if($index>=0 && $index<$n)
- $this->_items->itemAt($index)->setSelected(true);
- }
- }
- $this->_cachedSelectedIndices=$indices;
- }
- else
- throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedIndices($indices);
- }
-
- /**
- * @return TListItem|null the selected item with the lowest cardinal index, null if no item is selected.
- */
- public function getSelectedItem()
- {
- if(($index=$this->getSelectedIndex())>=0)
- return $this->_items->itemAt($index);
- else
- return null;
- }
-
- /**
- * Returns the value of the selected item with the lowest cardinal index.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getSelectedValue()}.
- * @return string the value of the selected item with the lowest cardinal index, empty if no selection.
- * @see getSelectedValue
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Selects an item by the specified value.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setSelectedValue()}.
- * @param string the value of the item to be selected.
- * @see setSelectedValue
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setSelectedValue($value);
- }
-
- /**
- * @return string the value of the selected item with the lowest cardinal index, empty if no selection
- */
- public function getSelectedValue()
- {
- $index=$this->getSelectedIndex();
- return $index>=0?$this->getItems()->itemAt($index)->getValue():'';
- }
-
- /**
- * Sets selection by item value.
- * Existing selections will be cleared if the item value is found in the item collection.
- * Note, if the value is null, existing selections will also be cleared.
- * @param string the value of the item to be selected.
- */
- public function setSelectedValue($value)
- {
- if($this->_items)
- {
- if($value===null)
- $this->clearSelection();
- else if(($item=$this->_items->findItemByValue($value))!==null)
- {
- $this->clearSelection();
- $item->setSelected(true);
- }
- else
- $this->clearSelection();
- }
- $this->_cachedSelectedValue=$value;
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedValue($value);
- }
-
-
- /**
- * @return array list of the selected item values (strings)
- */
- public function getSelectedValues()
- {
- $values=array();
- if($this->_items)
- {
- foreach($this->_items as $item)
- {
- if($item->getSelected())
- $values[]=$item->getValue();
- }
- }
- return $values;
- }
-
- /**
- * @param array list of the selected item values
- */
- public function setSelectedValues($values)
- {
- if($this->getIsMultiSelect())
- {
- if($this->_items)
- {
- $this->clearSelection();
- $lookup=array();
- foreach($this->_items as $item)
- $lookup[$item->getValue()]=$item;
- foreach($values as $value)
- {
- if(isset($lookup["$value"]))
- $lookup["$value"]->setSelected(true);
- }
- }
- $this->_cachedSelectedValues=$values;
- }
- else
- throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedValues($values);
- }
-
- /**
- * @return string selected value
- */
- public function getText()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * @param string value to be selected
- */
- public function setText($value)
- {
- $this->setSelectedValue($value);
- }
-
- /**
- * Clears all existing selections.
- */
- public function clearSelection()
- {
- if($this->_items)
- {
- foreach($this->_items as $item)
- $item->setSelected(false);
- }
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->clearSelection();
- }
-
- /**
- * @return string the group of validators which the list control causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the list control causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the prompt text which is to be displayed as the first list item.
- * @since 3.1.1
- */
- public function getPromptText()
- {
- return $this->getViewState('PromptText','');
- }
-
- /**
- * @param string the prompt text which is to be displayed as the first list item.
- * @since 3.1.1
- */
- public function setPromptText($value)
- {
- $this->setViewState('PromptText',$value,'');
- }
-
- /**
- * @return string the prompt selection value.
- * @see getPromptText
- * @since 3.1.1
- */
- public function getPromptValue()
- {
- return $this->getViewState('PromptValue','');
- }
-
- /**
- * @param string the prompt selection value. If empty, {@link getPromptText PromptText} will be used as the value.
- * @see setPromptText
- * @since 3.1.1
- */
- public function setPromptValue($value)
- {
- $this->setViewState('PromptValue',(string)$value,'');
- }
-
- /**
- * Raises OnSelectedIndexChanged event when selection is changed.
- * This method is invoked when the list control has its selection changed
- * by end-users.
- * @param TEventParameter event parameter
- */
- public function onSelectedIndexChanged($param)
- {
- $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
- $this->onTextChanged($param);
- }
-
- /**
- * Raises OnTextChanged event when selection is changed.
- * This method is invoked when the list control has its selection changed
- * by end-users.
- * @param TEventParameter event parameter
- */
- public function onTextChanged($param)
- {
- $this->raiseEvent('OnTextChanged',$this,$param);
- }
-
- /**
- * Renders the prompt text, if any.
- * @param THtmlWriter writer
- * @since 3.1.1
- */
- protected function renderPrompt($writer)
- {
- $text=$this->getPromptText();
- $value=$this->getPromptValue();
- if($value==='')
- $value=$text;
- if($value!=='')
- {
- $writer->addAttribute('value',$value);
- $writer->renderBeginTag('option');
- $writer->write(THttpUtility::htmlEncode($text));
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
-
- /**
- * Renders body content of the list control.
- * This method renders items contained in the list control as the body content.
- * @param THtmlWriter writer
- */
- public function renderContents($writer)
- {
- $this->renderPrompt($writer);
-
- if($this->_items)
- {
- $writer->writeLine();
- $previousGroup=null;
- foreach($this->_items as $item)
- {
- if($item->getEnabled())
- {
- if($item->getHasAttributes())
- {
- $group=$item->getAttributes()->remove('Group');
- if($group!==$previousGroup)
- {
- if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $previousGroup=null;
- }
- if($group!==null)
- {
- $writer->addAttribute('label',$group);
- $writer->renderBeginTag('optgroup');
- $writer->writeLine();
- $previousGroup=$group;
- }
- }
- foreach($item->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
- else if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $previousGroup=null;
- }
- if($item->getSelected())
- $writer->addAttribute('selected','selected');
- $writer->addAttribute('value',$item->getValue());
- $writer->renderBeginTag('option');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
- if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
- }
-
- /**
- * Formats the text value according to a format string.
- * If the format string is empty, the original value is converted into
- * a string and returned.
- * If the format string starts with '#', the string is treated as a PHP expression
- * within which the token '{0}' is translated with the data value to be formated.
- * Otherwise, the format string and the data value are passed
- * as the first and second parameters in {@link sprintf}.
- * @param string format string
- * @param mixed the data to be formatted
- * @return string the formatted result
- */
- protected function formatDataValue($formatString,$value)
- {
- if($formatString==='')
- return TPropertyValue::ensureString($value);
- else if($formatString[0]==='#')
- {
- $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
- try
- {
- if(eval("\$result=$expression;")===false)
- throw new Exception('');
- return $result;
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('listcontrol_expression_invalid',get_class($this),$expression,$e->getMessage());
- }
- }
- else
- return sprintf($formatString,$value);
- }
-}
-
-/**
- * IListControlAdapter interface
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Revision: $ Sun Jun 25 04:53:43 EST 2006 $
- * @package System.Web.UI.ActiveControls
- * @since 3.0
- */
-interface IListControlAdapter
-{
- /**
- * Selects an item based on zero-base index on the client side.
- * @param integer the index (zero-based) of the item to be selected
- */
- public function setSelectedIndex($index);
- /**
- * Selects a list of item based on zero-base indices on the client side.
- * @param array list of index of items to be selected
- */
- public function setSelectedIndices($indices);
-
- /**
- * Sets selection by item value on the client side.
- * @param string the value of the item to be selected.
- */
- public function setSelectedValue($value);
-
- /**
- * Sets selection by a list of item values on the client side.
- * @param array list of the selected item values
- */
- public function setSelectedValues($values);
-
- /**
- * Clears all existing selections on the client side.
- */
- public function clearSelection();
-}
-
-
-?>
+<?php + +/** + * TListControl class file + * + * @author Robin J. Rogge <rojaro@gmail.com> + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes the supporting classes + */ +Prado::using('System.Web.UI.WebControls.TDataBoundControl'); +Prado::using('System.Web.UI.WebControls.TListItem'); +Prado::using('System.Collections.TListItemCollection'); +Prado::using('System.Collections.TAttributeCollection'); +Prado::using('System.Util.TDataFieldAccessor'); + +/** + * TListControl class + * + * TListControl is a base class for list controls, such as {@link TListBox}, + * {@link TDropDownList}, {@link TCheckBoxList}, etc. + * It manages the items and their status in a list control. + * It also implements how the items can be populated from template and + * data source. + * + * The property {@link getItems} returns a list of the items in the control. + * To specify or determine which item is selected, use the + * {@link getSelectedIndex SelectedIndex} property that indicates the zero-based + * index of the selected item in the item list. You may also use + * {@link getSelectedItem SelectedItem} and {@link getSelectedValue SelectedValue} + * to get the selected item and its value. For multiple selection lists + * (such as {@link TCheckBoxList} and {@link TListBox}), property + * {@link getSelectedIndices SelectedIndices} is useful. + * + * TListControl implements {@link setAutoPostBack AutoPostBack} which allows + * a list control to postback the page if the selections of the list items are changed. + * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup} + * properties may be used to specify that validation be performed when auto postback occurs. + * + * There are three ways to populate the items in a list control: from template, + * using {@link setDataSource DataSource} and using {@link setDataSourceID DataSourceID}. + * The latter two are covered in {@link TDataBoundControl}. To specify items via + * template, using the following template syntax: + * <code> + * <com:TListControl> + * <com:TListItem Value="xxx" Text="yyy" > + * <com:TListItem Value="xxx" Text="yyy" Selected="true" > + * <com:TListItem Value="xxx" Text="yyy" > + * </com:TListControl> + * </code> + * + * When {@link setDataSource DataSource} or {@link setDataSourceID DataSourceID} + * is used to populate list items, the {@link setDataTextField DataTextField} and + * {@link setDataValueField DataValueField} properties are used to specify which + * columns of the data will be used to populate the text and value of the items. + * For example, if a data source is as follows, + * <code> + * $dataSource=array( + * array('name'=>'John', 'age'=>31), + * array('name'=>'Cary', 'age'=>28), + * array('name'=>'Rose', 'age'=>35), + * ); + * </code> + * setting {@link setDataTextField DataTextField} and {@link setDataValueField DataValueField} + * to 'name' and 'age' will make the first item's text be 'John', value be 31, + * the second item's text be 'Cary', value be 28, and so on. + * The {@link setDataTextFormatString DataTextFormatString} property may be further + * used to format how the item should be displayed. See {@link formatDataValue()} + * for an explanation of the format string. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +abstract class TListControl extends TDataBoundControl implements IDataRenderer +{ + /** + * @var TListItemCollection item list + */ + private $_items=null; + /** + * @var boolean whether items are restored from viewstate + */ + private $_stateLoaded=false; + /** + * @var mixed the following selection variables are used + * to keep selections when Items are not available + */ + private $_cachedSelectedIndex=-1; + private $_cachedSelectedValue=null; + private $_cachedSelectedIndices=null; + private $_cachedSelectedValues=null; + + /** + * @return string tag name of the list control + */ + protected function getTagName() + { + return 'select'; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + $page=$this->getPage(); + $page->ensureRenderInForm($this); + if($this->getIsMultiSelect()) + $writer->addAttribute('multiple','multiple'); + if($this->getEnabled(true)) + { + if($this->getAutoPostBack() + && $this->getEnableClientScript() + && $page->getClientSupportsJavaScript()) + { + $this->renderClientControlScript($writer); + } + } + else if($this->getEnabled()) + $writer->addAttribute('disabled','disabled'); + parent::addAttributesToRender($writer); + } + + /** + * Renders the javascript for list control. + */ + protected function renderClientControlScript($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * Derived classes may override this method and return customized js class names. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TListControl'; + } + + /** + * @return array postback options for JS postback code + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TListItem} objects into the {@link getItems Items} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + // Do not add items from template if items are loaded from viewstate + if(!$this->_stateLoaded && ($object instanceof TListItem)) + { + $index=$this->getItems()->add($object); + if(($this->_cachedSelectedValue!==null && $this->_cachedSelectedValue===$object->getValue()) || ($this->_cachedSelectedIndex===$index)) + { + $object->setSelected(true); + $this->_cachedSelectedValue=null; + $this->_cachedSelectedIndex=-1; + } + } + } + + /** + * Performs databinding to populate list items from data source. + * This method is invoked by dataBind(). + * You may override this function to provide your own way of data population. + * @param Traversable the data + */ + protected function performDataBinding($data) + { + $items=$this->getItems(); + if(!$this->getAppendDataBoundItems()) + $items->clear(); + $textField=$this->getDataTextField(); + if($textField==='') + $textField=0; + $valueField=$this->getDataValueField(); + if($valueField==='') + $valueField=1; + $textFormat=$this->getDataTextFormatString(); + $groupField=$this->getDataGroupField(); + foreach($data as $key=>$object) + { + $item=$items->createListItem(); + if(is_array($object) || is_object($object)) + { + $text=TDataFieldAccessor::getDataFieldValue($object,$textField); + $value=TDataFieldAccessor::getDataFieldValue($object,$valueField); + $item->setValue($value); + if($groupField!=='') + $item->setAttribute('Group',TDataFieldAccessor::getDataFieldValue($object,$groupField)); + } + else + { + $text=$object; + $item->setValue("$key"); + } + $item->setText($this->formatDataValue($textFormat,$text)); + } + // SelectedValue or SelectedIndex may be set before databinding + // so we make them be effective now + if($this->_cachedSelectedValue!==null) + { + $this->setSelectedValue($this->_cachedSelectedValue); + $this->resetCachedSelections(); + } + else if($this->_cachedSelectedIndex!==-1) + { + $this->setSelectedIndex($this->_cachedSelectedIndex); + $this->resetCachedSelections(); + } + else if($this->_cachedSelectedValues!==null) + { + $this->setSelectedValues($this->_cachedSelectedValues); + $this->resetCachedSelections(); + } + else if($this->_cachedSelectedIndices!==null) + { + $this->setSelectedIndices($this->_cachedSelectedIndices); + $this->resetCachedSelections(); + } + } + + private function resetCachedSelections() + { + $this->_cachedSelectedValue=null; + $this->_cachedSelectedIndex=-1; + $this->_cachedSelectedValues=null; + $this->_cachedSelectedIndices=null; + } + + /** + * Creates a collection object to hold list items. + * This method may be overriden to create a customized collection. + * @return TListItemCollection the collection object + */ + protected function createListItemCollection() + { + return new TListItemCollection; + } + + /** + * Saves items into viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if($this->_items) + $this->setViewState('Items',$this->_items->saveState(),null); + else + $this->clearViewState('Items'); + } + + /** + * Loads items from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + $this->_stateLoaded=true; + if(!$this->getIsDataBound()) + { + $this->_items=$this->createListItemCollection(); + $this->_items->loadState($this->getViewState('Items',null)); + } + $this->clearViewState('Items'); + } + + /** + * @return boolean whether this is a multiselect control. Defaults to false. + */ + protected function getIsMultiSelect() + { + return false; + } + + /** + * @return boolean whether performing databind should append items or clear the existing ones. Defaults to false. + */ + public function getAppendDataBoundItems() + { + return $this->getViewState('AppendDataBoundItems',false); + } + + /** + * @param boolean whether performing databind should append items or clear the existing ones. + */ + public function setAppendDataBoundItems($value) + { + $this->setViewState('AppendDataBoundItems',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean a value indicating whether an automatic postback to the server + * will occur whenever the user makes change to the list control and then tabs out of it. + * Defaults to false. + */ + public function getAutoPostBack() + { + return $this->getViewState('AutoPostBack',false); + } + + /** + * Sets the value indicating if postback automatically. + * An automatic postback to the server will occur whenever the user + * makes change to the list control and then tabs out of it. + * @param boolean the value indicating if postback automatically + */ + public function setAutoPostBack($value) + { + $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether postback event trigger by this list control will cause input validation, default is true. + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this list control will cause input validation. + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string the field of the data source that provides the text content of the list items. + */ + public function getDataTextField() + { + return $this->getViewState('DataTextField',''); + } + + /** + * @param string the field of the data source that provides the text content of the list items. + */ + public function setDataTextField($value) + { + $this->setViewState('DataTextField',$value,''); + } + + /** + * @return string the formatting string used to control how data bound to the list control is displayed. + */ + public function getDataTextFormatString() + { + return $this->getViewState('DataTextFormatString',''); + } + + /** + * Sets data text format string. + * The format string is used in {@link TDataValueFormatter::format()} to format the Text property value + * of each item in the list control. + * @param string the formatting string used to control how data bound to the list control is displayed. + * @see TDataValueFormatter::format() + */ + public function setDataTextFormatString($value) + { + $this->setViewState('DataTextFormatString',$value,''); + } + + /** + * @return string the field of the data source that provides the value of each list item. + */ + public function getDataValueField() + { + return $this->getViewState('DataValueField',''); + } + + /** + * @param string the field of the data source that provides the value of each list item. + */ + public function setDataValueField($value) + { + $this->setViewState('DataValueField',$value,''); + } + + /** + * @return string the field of the data source that provides the label of the list item groups + */ + public function getDataGroupField() + { + return $this->getViewState('DataGroupField',''); + } + + /** + * @param string the field of the data source that provides the label of the list item groups + */ + public function setDataGroupField($value) + { + $this->setViewState('DataGroupField',$value,''); + } + + /** + * @return integer the number of items in the list control + */ + public function getItemCount() + { + return $this->_items?$this->_items->getCount():0; + } + + /** + * @return boolean whether the list control contains any items. + */ + public function getHasItems() + { + return ($this->_items && $this->_items->getCount()>0); + } + + /** + * @return TListItemCollection the item collection + */ + public function getItems() + { + if(!$this->_items) + $this->_items=$this->createListItemCollection(); + return $this->_items; + } + + /** + * @return integer the index (zero-based) of the item being selected, -1 if no item is selected. + */ + public function getSelectedIndex() + { + if($this->_items) + { + $n=$this->_items->getCount(); + for($i=0;$i<$n;++$i) + if($this->_items->itemAt($i)->getSelected()) + return $i; + } + return -1; + } + + /** + * @param integer the index (zero-based) of the item to be selected + */ + public function setSelectedIndex($index) + { + if(($index=TPropertyValue::ensureInteger($index))<0) + $index=-1; + if($this->_items) + { + $this->clearSelection(); + if($index>=0 && $index<$this->_items->getCount()) + $this->_items->itemAt($index)->setSelected(true); + } + $this->_cachedSelectedIndex=$index; + if($this->getAdapter() instanceof IListControlAdapter) + $this->getAdapter()->setSelectedIndex($index); + } + + /** + * @return array list of index of items that are selected + */ + public function getSelectedIndices() + { + $selections=array(); + if($this->_items) + { + $n=$this->_items->getCount(); + for($i=0;$i<$n;++$i) + if($this->_items->itemAt($i)->getSelected()) + $selections[]=$i; + } + return $selections; + } + + /** + * @param array list of index of items to be selected + */ + public function setSelectedIndices($indices) + { + if($this->getIsMultiSelect()) + { + if($this->_items) + { + $this->clearSelection(); + $n=$this->_items->getCount(); + foreach($indices as $index) + { + if($index>=0 && $index<$n) + $this->_items->itemAt($index)->setSelected(true); + } + } + $this->_cachedSelectedIndices=$indices; + } + else + throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this)); + + if($this->getAdapter() instanceof IListControlAdapter) + $this->getAdapter()->setSelectedIndices($indices); + } + + /** + * @return TListItem|null the selected item with the lowest cardinal index, null if no item is selected. + */ + public function getSelectedItem() + { + if(($index=$this->getSelectedIndex())>=0) + return $this->_items->itemAt($index); + else + return null; + } + + /** + * Returns the value of the selected item with the lowest cardinal index. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getSelectedValue()}. + * @return string the value of the selected item with the lowest cardinal index, empty if no selection. + * @see getSelectedValue + * @since 3.1.0 + */ + public function getData() + { + return $this->getSelectedValue(); + } + + /** + * Selects an item by the specified value. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setSelectedValue()}. + * @param string the value of the item to be selected. + * @see setSelectedValue + * @since 3.1.0 + */ + public function setData($value) + { + $this->setSelectedValue($value); + } + + /** + * @return string the value of the selected item with the lowest cardinal index, empty if no selection + */ + public function getSelectedValue() + { + $index=$this->getSelectedIndex(); + return $index>=0?$this->getItems()->itemAt($index)->getValue():''; + } + + /** + * Sets selection by item value. + * Existing selections will be cleared if the item value is found in the item collection. + * Note, if the value is null, existing selections will also be cleared. + * @param string the value of the item to be selected. + */ + public function setSelectedValue($value) + { + if($this->_items) + { + if($value===null) + $this->clearSelection(); + else if(($item=$this->_items->findItemByValue($value))!==null) + { + $this->clearSelection(); + $item->setSelected(true); + } + else + $this->clearSelection(); + } + $this->_cachedSelectedValue=$value; + if($this->getAdapter() instanceof IListControlAdapter) + $this->getAdapter()->setSelectedValue($value); + } + + + /** + * @return array list of the selected item values (strings) + */ + public function getSelectedValues() + { + $values=array(); + if($this->_items) + { + foreach($this->_items as $item) + { + if($item->getSelected()) + $values[]=$item->getValue(); + } + } + return $values; + } + + /** + * @param array list of the selected item values + */ + public function setSelectedValues($values) + { + if($this->getIsMultiSelect()) + { + if($this->_items) + { + $this->clearSelection(); + $lookup=array(); + foreach($this->_items as $item) + $lookup[$item->getValue()]=$item; + foreach($values as $value) + { + if(isset($lookup["$value"])) + $lookup["$value"]->setSelected(true); + } + } + $this->_cachedSelectedValues=$values; + } + else + throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this)); + + if($this->getAdapter() instanceof IListControlAdapter) + $this->getAdapter()->setSelectedValues($values); + } + + /** + * @return string selected value + */ + public function getText() + { + return $this->getSelectedValue(); + } + + /** + * @param string value to be selected + */ + public function setText($value) + { + $this->setSelectedValue($value); + } + + /** + * Clears all existing selections. + */ + public function clearSelection() + { + if($this->_items) + { + foreach($this->_items as $item) + $item->setSelected(false); + } + + if($this->getAdapter() instanceof IListControlAdapter) + $this->getAdapter()->clearSelection(); + } + + /** + * @return string the group of validators which the list control causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the list control causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return string the prompt text which is to be displayed as the first list item. + * @since 3.1.1 + */ + public function getPromptText() + { + return $this->getViewState('PromptText',''); + } + + /** + * @param string the prompt text which is to be displayed as the first list item. + * @since 3.1.1 + */ + public function setPromptText($value) + { + $this->setViewState('PromptText',$value,''); + } + + /** + * @return string the prompt selection value. + * @see getPromptText + * @since 3.1.1 + */ + public function getPromptValue() + { + return $this->getViewState('PromptValue',''); + } + + /** + * @param string the prompt selection value. If empty, {@link getPromptText PromptText} will be used as the value. + * @see setPromptText + * @since 3.1.1 + */ + public function setPromptValue($value) + { + $this->setViewState('PromptValue',(string)$value,''); + } + + /** + * Raises OnSelectedIndexChanged event when selection is changed. + * This method is invoked when the list control has its selection changed + * by end-users. + * @param TEventParameter event parameter + */ + public function onSelectedIndexChanged($param) + { + $this->raiseEvent('OnSelectedIndexChanged',$this,$param); + $this->onTextChanged($param); + } + + /** + * Raises OnTextChanged event when selection is changed. + * This method is invoked when the list control has its selection changed + * by end-users. + * @param TEventParameter event parameter + */ + public function onTextChanged($param) + { + $this->raiseEvent('OnTextChanged',$this,$param); + } + + /** + * Renders the prompt text, if any. + * @param THtmlWriter writer + * @since 3.1.1 + */ + protected function renderPrompt($writer) + { + $text=$this->getPromptText(); + $value=$this->getPromptValue(); + if($value==='') + $value=$text; + if($value!=='') + { + $writer->addAttribute('value',$value); + $writer->renderBeginTag('option'); + $writer->write(THttpUtility::htmlEncode($text)); + $writer->renderEndTag(); + $writer->writeLine(); + } + } + + /** + * Renders body content of the list control. + * This method renders items contained in the list control as the body content. + * @param THtmlWriter writer + */ + public function renderContents($writer) + { + $this->renderPrompt($writer); + + if($this->_items) + { + $writer->writeLine(); + $previousGroup=null; + foreach($this->_items as $item) + { + if($item->getEnabled()) + { + if($item->getHasAttributes()) + { + $group=$item->getAttributes()->remove('Group'); + if($group!==$previousGroup) + { + if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + $previousGroup=null; + } + if($group!==null) + { + $writer->addAttribute('label',$group); + $writer->renderBeginTag('optgroup'); + $writer->writeLine(); + $previousGroup=$group; + } + } + foreach($item->getAttributes() as $name=>$value) + $writer->addAttribute($name,$value); + } + else if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + $previousGroup=null; + } + if($item->getSelected()) + $writer->addAttribute('selected','selected'); + $writer->addAttribute('value',$item->getValue()); + $writer->renderBeginTag('option'); + $writer->write(THttpUtility::htmlEncode($item->getText())); + $writer->renderEndTag(); + $writer->writeLine(); + } + } + if($previousGroup!==null) + { + $writer->renderEndTag(); + $writer->writeLine(); + } + } + } + + /** + * Formats the text value according to a format string. + * If the format string is empty, the original value is converted into + * a string and returned. + * If the format string starts with '#', the string is treated as a PHP expression + * within which the token '{0}' is translated with the data value to be formated. + * Otherwise, the format string and the data value are passed + * as the first and second parameters in {@link sprintf}. + * @param string format string + * @param mixed the data to be formatted + * @return string the formatted result + */ + protected function formatDataValue($formatString,$value) + { + if($formatString==='') + return TPropertyValue::ensureString($value); + else if($formatString[0]==='#') + { + $expression=strtr(substr($formatString,1),array('{0}'=>'$value')); + try + { + if(eval("\$result=$expression;")===false) + throw new Exception(''); + return $result; + } + catch(Exception $e) + { + throw new TInvalidDataValueException('listcontrol_expression_invalid',get_class($this),$expression,$e->getMessage()); + } + } + else + return sprintf($formatString,$value); + } +} + +/** + * IListControlAdapter interface + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Revision: $ Sun Jun 25 04:53:43 EST 2006 $ + * @package System.Web.UI.ActiveControls + * @since 3.0 + */ +interface IListControlAdapter +{ + /** + * Selects an item based on zero-base index on the client side. + * @param integer the index (zero-based) of the item to be selected + */ + public function setSelectedIndex($index); + /** + * Selects a list of item based on zero-base indices on the client side. + * @param array list of index of items to be selected + */ + public function setSelectedIndices($indices); + + /** + * Sets selection by item value on the client side. + * @param string the value of the item to be selected. + */ + public function setSelectedValue($value); + + /** + * Sets selection by a list of item values on the client side. + * @param array list of the selected item values + */ + public function setSelectedValues($values); + + /** + * Clears all existing selections on the client side. + */ + public function clearSelection(); +} + + +?> diff --git a/framework/Web/UI/WebControls/TListControlValidator.php b/framework/Web/UI/WebControls/TListControlValidator.php index a5be67b3..75a0510c 100644 --- a/framework/Web/UI/WebControls/TListControlValidator.php +++ b/framework/Web/UI/WebControls/TListControlValidator.php @@ -1,225 +1,225 @@ -<?php
-/**
- * TListControlValidator class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TListControlValidator class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TListControlValidator class.
- *
- * TListControlValidator checks the number of selection and their values
- * for a <b>TListControl that allows multiple selection</b>.
- *
- * You can specify the minimum or maximum (or both) number of selections
- * required using the {@link setMinSelection MinSelection} and
- * {@link setMaxSelection MaxSelection} properties, respectively. In addition,
- * you can specify a comma separated list of required selected values via the
- * {@link setRequiredSelections RequiredSelections} property.
- *
- * Examples
- * - At least two selections
- * <code>
- * <com:TListBox ID="listbox" SelectionMode="Multiple">
- * <com:TListItem Text="item1" Value="value1" />
- * <com:TListItem Text="item2" Value="value2" />
- * <com:TListItem Text="item3" Value="value3" />
- * </com:TListBox>
- *
- * <com:TListControlValidator
- * ControlToValidate="listbox"
- * MinSelection="2"
- * ErrorMessage="Please select at least 2" />
- * </code>
- * - "value1" must be selected <b>and</b> at least 1 other
- * <code>
- * <com:TCheckBoxList ID="checkboxes">
- * <com:TListItem Text="item1" Value="value1" />
- * <com:TListItem Text="item2" Value="value2" />
- * <com:TListItem Text="item3" Value="value3" />
- * </com:TCheckBoxList>
- *
- * <com:TListControlValidator
- * ControlToValidate="checkboxes"
- * RequiredSelections="value1"
- * MinSelection="2"
- * ErrorMessage="Please select 'item1' and at least 1 other" />
- * </code>
- *
- * @author Xiang Wei Zhuo <weizhuo[at]gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListControlValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListControlValidator';
- }
-
- /**
- * @return integer min number of selections. Defaults to -1, meaning not set.
- */
- public function getMinSelection()
- {
- return $this->getViewState('MinSelection',-1);
- }
-
- /**
- * @param integer minimum number of selections.
- */
- public function setMinSelection($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- $this->setViewState('MinSelection',$value,-1);
- }
-
- /**
- * @return integer max number of selections. Defaults to -1, meaning not set.
- */
- public function getMaxSelection()
- {
- return $this->getViewState('MaxSelection',-1);
- }
-
- /**
- * @param integer max number of selections.
- */
- public function setMaxSelection($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- $this->setViewState('MaxSelection',$value,-1);
- }
-
- /**
- * Get a comma separated list of required selected values.
- * @return string comma separated list of required values.
- */
- public function getRequiredSelections()
- {
- return $this->getViewState('RequiredSelections','');
- }
-
- /**
- * Set the list of required values, using aa comma separated list.
- * @param string comma separated list of required values.
- */
- public function setRequiredSelections($value)
- {
- $this->setViewState('RequiredSelections',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input component changes its data
- * from the InitialValue or the input component is not given.
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $control=$this->getValidationTarget();
-
- $exists = true;
- $values = $this->getSelection($control);
- $count = count($values);
- $required = $this->getRequiredValues();
-
- //if required, check the values
- if(!empty($required))
- {
- if($count < count($required) )
- return false;
- foreach($required as $require)
- $exists = $exists && in_array($require, $values);
- }
-
- $min = $this->getMinSelection();
- $max = $this->getMaxSelection();
-
- if($min !== -1 && $max !== -1)
- return $exists && $count >= $min && $count <= $max;
- else if($min === -1 && $max !== -1)
- return $exists && $count <= $max;
- else if($min !== -1 && $max === -1)
- return $exists && $count >= $min;
- else
- return $exists;
- }
-
- /**
- * @param TListControl control to validate
- * @return array number of selected values and its values.
- */
- protected function getSelection($control)
- {
- $values = array();
-
- //get the data
- foreach($control->getItems() as $item)
- {
- if($item->getSelected())
- $values[] = $item->getValue();
- }
- return $values;
- }
-
- /**
- * @return array list of required values.
- */
- protected function getRequiredValues()
- {
- $required = array();
- $string = $this->getRequiredSelections();
- if(!empty($string))
- $required = preg_split('/,\s*/', $string);
- return $required;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $control = $this->getValidationTarget();
-
- if(!$control instanceof TListControl)
- {
- throw new TConfigurationException(
- 'listcontrolvalidator_invalid_control',
- $this->getID(),$this->getControlToValidate(), get_class($control));
- }
-
- $min = $this->getMinSelection();
- $max = $this->getMaxSelection();
- if($min !== -1)
- $options['Min']= $min;
- if($max !== -1)
- $options['Max']= $max;
- $required = $this->getRequiredSelections();
- if(strlen($required) > 0)
- $options['Required']= $required;
- $options['TotalItems'] = $control->getItemCount();
-
- return $options;
- }
-}
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TListControlValidator class. + * + * TListControlValidator checks the number of selection and their values + * for a <b>TListControl that allows multiple selection</b>. + * + * You can specify the minimum or maximum (or both) number of selections + * required using the {@link setMinSelection MinSelection} and + * {@link setMaxSelection MaxSelection} properties, respectively. In addition, + * you can specify a comma separated list of required selected values via the + * {@link setRequiredSelections RequiredSelections} property. + * + * Examples + * - At least two selections + * <code> + * <com:TListBox ID="listbox" SelectionMode="Multiple"> + * <com:TListItem Text="item1" Value="value1" /> + * <com:TListItem Text="item2" Value="value2" /> + * <com:TListItem Text="item3" Value="value3" /> + * </com:TListBox> + * + * <com:TListControlValidator + * ControlToValidate="listbox" + * MinSelection="2" + * ErrorMessage="Please select at least 2" /> + * </code> + * - "value1" must be selected <b>and</b> at least 1 other + * <code> + * <com:TCheckBoxList ID="checkboxes"> + * <com:TListItem Text="item1" Value="value1" /> + * <com:TListItem Text="item2" Value="value2" /> + * <com:TListItem Text="item3" Value="value3" /> + * </com:TCheckBoxList> + * + * <com:TListControlValidator + * ControlToValidate="checkboxes" + * RequiredSelections="value1" + * MinSelection="2" + * ErrorMessage="Please select 'item1' and at least 1 other" /> + * </code> + * + * @author Xiang Wei Zhuo <weizhuo[at]gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TListControlValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TListControlValidator'; + } + + /** + * @return integer min number of selections. Defaults to -1, meaning not set. + */ + public function getMinSelection() + { + return $this->getViewState('MinSelection',-1); + } + + /** + * @param integer minimum number of selections. + */ + public function setMinSelection($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + $this->setViewState('MinSelection',$value,-1); + } + + /** + * @return integer max number of selections. Defaults to -1, meaning not set. + */ + public function getMaxSelection() + { + return $this->getViewState('MaxSelection',-1); + } + + /** + * @param integer max number of selections. + */ + public function setMaxSelection($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + $value=-1; + $this->setViewState('MaxSelection',$value,-1); + } + + /** + * Get a comma separated list of required selected values. + * @return string comma separated list of required values. + */ + public function getRequiredSelections() + { + return $this->getViewState('RequiredSelections',''); + } + + /** + * Set the list of required values, using aa comma separated list. + * @param string comma separated list of required values. + */ + public function setRequiredSelections($value) + { + $this->setViewState('RequiredSelections',$value,''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input component changes its data + * from the InitialValue or the input component is not given. + * @return boolean whether the validation succeeds + */ + protected function evaluateIsValid() + { + $control=$this->getValidationTarget(); + + $exists = true; + $values = $this->getSelection($control); + $count = count($values); + $required = $this->getRequiredValues(); + + //if required, check the values + if(!empty($required)) + { + if($count < count($required) ) + return false; + foreach($required as $require) + $exists = $exists && in_array($require, $values); + } + + $min = $this->getMinSelection(); + $max = $this->getMaxSelection(); + + if($min !== -1 && $max !== -1) + return $exists && $count >= $min && $count <= $max; + else if($min === -1 && $max !== -1) + return $exists && $count <= $max; + else if($min !== -1 && $max === -1) + return $exists && $count >= $min; + else + return $exists; + } + + /** + * @param TListControl control to validate + * @return array number of selected values and its values. + */ + protected function getSelection($control) + { + $values = array(); + + //get the data + foreach($control->getItems() as $item) + { + if($item->getSelected()) + $values[] = $item->getValue(); + } + return $values; + } + + /** + * @return array list of required values. + */ + protected function getRequiredValues() + { + $required = array(); + $string = $this->getRequiredSelections(); + if(!empty($string)) + $required = preg_split('/,\s*/', $string); + return $required; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $control = $this->getValidationTarget(); + + if(!$control instanceof TListControl) + { + throw new TConfigurationException( + 'listcontrolvalidator_invalid_control', + $this->getID(),$this->getControlToValidate(), get_class($control)); + } + + $min = $this->getMinSelection(); + $max = $this->getMaxSelection(); + if($min !== -1) + $options['Min']= $min; + if($max !== -1) + $options['Max']= $max; + $required = $this->getRequiredSelections(); + if(strlen($required) > 0) + $options['Required']= $required; + $options['TotalItems'] = $control->getItemCount(); + + return $options; + } +} diff --git a/framework/Web/UI/WebControls/TListItem.php b/framework/Web/UI/WebControls/TListItem.php index 354aa62a..e80bcafd 100644 --- a/framework/Web/UI/WebControls/TListItem.php +++ b/framework/Web/UI/WebControls/TListItem.php @@ -1,184 +1,184 @@ -<?php
-/**
- * TListItem class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TListItem class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TListItem class.
- *
- * TListItem represents an item in a list control. Each item has a {@link setText Text}
- * property and a {@link setValue Value} property. If either one of them is not set,
- * it will take the value of the other property.
- * An item can be {@link setSelected Selected} or {@link setEnabled Enabled},
- * and it can have additional {@link getAttributes Attributes} which may be rendered
- * if the list control supports so.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListItem extends TComponent
-{
- /**
- * @var TMap list of custom attributes
- */
- private $_attributes=null;
- /**
- * @var string text of the item
- */
- private $_text;
- /**
- * @var string value of the item
- */
- private $_value;
- /**
- * @var boolean whether the item is enabled
- */
- private $_enabled;
- /**
- * @var boolean whether the item is selected
- */
- private $_selected;
-
- /**
- * Constructor.
- * @param string text of the item
- * @param string value of the item
- * @param boolean whether the item is enabled
- * @param boolean whether the item is selected
- */
- public function __construct($text='',$value='',$enabled=true,$selected=false)
- {
- $this->setText($text);
- $this->setValue($value);
- $this->setEnabled($enabled);
- $this->setSelected($selected);
- }
-
- /**
- * @return boolean whether the item is enabled
- */
- public function getEnabled()
- {
- return $this->_enabled;
- }
-
- /**
- * @param boolean whether the item is enabled
- */
- public function setEnabled($value)
- {
- $this->_enabled=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether the item is selected
- */
- public function getSelected()
- {
- return $this->_selected;
- }
-
- /**
- * @param boolean whether the item is selected
- */
- public function setSelected($value)
- {
- $this->_selected=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return string text of the item
- */
- public function getText()
- {
- return $this->_text===''?$this->_value:$this->_text;
- }
-
- /**
- * @param string text of the item
- */
- public function setText($value)
- {
- $this->_text=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return string value of the item
- */
- public function getValue()
- {
- return $this->_value===''?$this->_text:$this->_value;
- }
-
- /**
- * @param string value of the item
- */
- public function setValue($value)
- {
- $this->_value=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return TAttributeCollection custom attributes
- */
- public function getAttributes()
- {
- if(!$this->_attributes)
- $this->_attributes=new TAttributeCollection;
- return $this->_attributes;
- }
-
- /**
- * @return boolean whether the item has any custom attribute
- */
- public function getHasAttributes()
- {
- return $this->_attributes && $this->_attributes->getCount()>0;
- }
-
- /**
- * @param string name of the attribute
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- return $this->_attributes?$this->_attributes->contains($name):false;
- }
-
- /**
- * @return string the named attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- return $this->_attributes?$this->_attributes->itemAt($name):null;
- }
-
- /**
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, empty string if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- return $this->_attributes?$this->_attributes->remove($name):null;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TListItem class. + * + * TListItem represents an item in a list control. Each item has a {@link setText Text} + * property and a {@link setValue Value} property. If either one of them is not set, + * it will take the value of the other property. + * An item can be {@link setSelected Selected} or {@link setEnabled Enabled}, + * and it can have additional {@link getAttributes Attributes} which may be rendered + * if the list control supports so. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TListItem extends TComponent +{ + /** + * @var TMap list of custom attributes + */ + private $_attributes=null; + /** + * @var string text of the item + */ + private $_text; + /** + * @var string value of the item + */ + private $_value; + /** + * @var boolean whether the item is enabled + */ + private $_enabled; + /** + * @var boolean whether the item is selected + */ + private $_selected; + + /** + * Constructor. + * @param string text of the item + * @param string value of the item + * @param boolean whether the item is enabled + * @param boolean whether the item is selected + */ + public function __construct($text='',$value='',$enabled=true,$selected=false) + { + $this->setText($text); + $this->setValue($value); + $this->setEnabled($enabled); + $this->setSelected($selected); + } + + /** + * @return boolean whether the item is enabled + */ + public function getEnabled() + { + return $this->_enabled; + } + + /** + * @param boolean whether the item is enabled + */ + public function setEnabled($value) + { + $this->_enabled=TPropertyValue::ensureBoolean($value); + } + + /** + * @return boolean whether the item is selected + */ + public function getSelected() + { + return $this->_selected; + } + + /** + * @param boolean whether the item is selected + */ + public function setSelected($value) + { + $this->_selected=TPropertyValue::ensureBoolean($value); + } + + /** + * @return string text of the item + */ + public function getText() + { + return $this->_text===''?$this->_value:$this->_text; + } + + /** + * @param string text of the item + */ + public function setText($value) + { + $this->_text=TPropertyValue::ensureString($value); + } + + /** + * @return string value of the item + */ + public function getValue() + { + return $this->_value===''?$this->_text:$this->_value; + } + + /** + * @param string value of the item + */ + public function setValue($value) + { + $this->_value=TPropertyValue::ensureString($value); + } + + /** + * @return TAttributeCollection custom attributes + */ + public function getAttributes() + { + if(!$this->_attributes) + $this->_attributes=new TAttributeCollection; + return $this->_attributes; + } + + /** + * @return boolean whether the item has any custom attribute + */ + public function getHasAttributes() + { + return $this->_attributes && $this->_attributes->getCount()>0; + } + + /** + * @param string name of the attribute + * @return boolean whether the named attribute exists + */ + public function hasAttribute($name) + { + return $this->_attributes?$this->_attributes->contains($name):false; + } + + /** + * @return string the named attribute value, null if attribute does not exist + */ + public function getAttribute($name) + { + return $this->_attributes?$this->_attributes->itemAt($name):null; + } + + /** + * @param string attribute name + * @param string value of the attribute + */ + public function setAttribute($name,$value) + { + $this->getAttributes()->add($name,$value); + } + + /** + * Removes the named attribute. + * @param string the name of the attribute to be removed. + * @return string attribute value removed, empty string if attribute does not exist. + */ + public function removeAttribute($name) + { + return $this->_attributes?$this->_attributes->remove($name):null; + } +} + diff --git a/framework/Web/UI/WebControls/TLiteral.php b/framework/Web/UI/WebControls/TLiteral.php index 423e2d8e..e98d56bb 100644 --- a/framework/Web/UI/WebControls/TLiteral.php +++ b/framework/Web/UI/WebControls/TLiteral.php @@ -1,112 +1,112 @@ -<?php
-/**
- * TLiteral class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TLiteral class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLiteral class
- *
- * TLiteral displays a static text on the Web page.
- * TLiteral is similar to the TLabel control, except that the TLiteral
- * control does not have style properties (e.g. BackColor, Font, etc.)
- * You can programmatically control the text displayed in the control by setting
- * the {@link setText Text} property. The text displayed may be HTML-encoded
- * if the {@link setEncode Encode} property is set true (defaults to false).
- *
- * TLiteral will render the contents enclosed within its component tag
- * if {@link setText Text} is empty.
- *
- * Note, if {@link setEncode Encode} is false, make sure {@link setText Text}
- * does not contain unwanted characters that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLiteral extends TControl implements IDataRenderer
-{
- /**
- * @return string the static text of the TLiteral
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the static text of the TLiteral
- * @param string the text to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the static text of the TLiteral.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the static text of the TLiteral
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the static text of the TLiteral.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the static text of the TLiteral
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
- */
- public function getEncode()
- {
- return $this->getViewState('Encode',false);
- }
-
- /**
- * @param boolean whether the rendered text should be HTML-encoded.
- */
- public function setEncode($value)
- {
- $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Renders the literal control.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if(($text=$this->getText())!=='')
- {
- if($this->getEncode())
- $writer->write(THttpUtility::htmlEncode($text));
- else
- $writer->write($text);
- }
- else
- parent::render($writer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TLiteral class + * + * TLiteral displays a static text on the Web page. + * TLiteral is similar to the TLabel control, except that the TLiteral + * control does not have style properties (e.g. BackColor, Font, etc.) + * You can programmatically control the text displayed in the control by setting + * the {@link setText Text} property. The text displayed may be HTML-encoded + * if the {@link setEncode Encode} property is set true (defaults to false). + * + * TLiteral will render the contents enclosed within its component tag + * if {@link setText Text} is empty. + * + * Note, if {@link setEncode Encode} is false, make sure {@link setText Text} + * does not contain unwanted characters that may bring security vulnerabilities. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TLiteral extends TControl implements IDataRenderer +{ + /** + * @return string the static text of the TLiteral + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the static text of the TLiteral + * @param string the text to be set + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the static text of the TLiteral. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the static text of the TLiteral + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the static text of the TLiteral. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the static text of the TLiteral + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return boolean whether the rendered text should be HTML-encoded. Defaults to false. + */ + public function getEncode() + { + return $this->getViewState('Encode',false); + } + + /** + * @param boolean whether the rendered text should be HTML-encoded. + */ + public function setEncode($value) + { + $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Renders the literal control. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if(($text=$this->getText())!=='') + { + if($this->getEncode()) + $writer->write(THttpUtility::htmlEncode($text)); + else + $writer->write($text); + } + else + parent::render($writer); + } +} + diff --git a/framework/Web/UI/WebControls/TLiteralColumn.php b/framework/Web/UI/WebControls/TLiteralColumn.php index 5b1353fc..48cbe013 100644 --- a/framework/Web/UI/WebControls/TLiteralColumn.php +++ b/framework/Web/UI/WebControls/TLiteralColumn.php @@ -1,154 +1,154 @@ -<?php
-/**
- * TLiteralColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TLiteralColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TLiteralColumn class
- *
- * TLiteralColumn represents a static text column that is bound to a field in a data source.
- * The cells in the column will be displayed with static texts using the data indexed by
- * {@link setDataField DataField}. You can customize the display by
- * setting {@link setDataFormatString DataFormatString}.
- *
- * If {@link setDataField DataField} is not specified, the cells will be filled
- * with {@link setText Text}.
- *
- * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
- * @package System.Web.UI.WebControls
- * @since 3.0.5
- */
-class TLiteralColumn extends TDataGridColumn
-{
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataFormatString()
- {
- return $this->getViewState('DataFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataFormatString($value)
- {
- $this->setViewState('DataFormatString',$value,'');
- }
-
- /**
- * @return string static text to be displayed in the column. Defaults to empty.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string static text to be displayed in the column.
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
- */
- public function getEncode()
- {
- return $this->getViewState('Encode',false);
- }
-
- /**
- * @param boolean whether the rendered text should be HTML-encoded.
- */
- public function setEncode($value)
- {
- $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem)
- {
- if($this->getDataField()!=='')
- $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- else
- {
- if(($dataField=$this->getDataField())!=='')
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- else
- {
- $text=$this->getText();
- if($this->getEncode())
- $text=THttpUtility::htmlEncode($text);
- $cell->setText($text);
- }
- }
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- $formatString=$this->getDataFormatString();
- if(($field=$this->getDataField())!=='')
- $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
- else
- $value=$this->formatDataValue($formatString,$data);
- if($sender instanceof TTableCell)
- {
- if($this->getEncode())
- $value=THttpUtility::htmlEncode($value);
- $sender->setText($value);
- }
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TLiteralColumn class + * + * TLiteralColumn represents a static text column that is bound to a field in a data source. + * The cells in the column will be displayed with static texts using the data indexed by + * {@link setDataField DataField}. You can customize the display by + * setting {@link setDataFormatString DataFormatString}. + * + * If {@link setDataField DataField} is not specified, the cells will be filled + * with {@link setText Text}. + * + * If {@link setEncode Encode} is true, the static texts will be HTML-encoded. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $ + * @package System.Web.UI.WebControls + * @since 3.0.5 + */ +class TLiteralColumn extends TDataGridColumn +{ + /** + * @return string the field name from the data source to bind to the column + */ + public function getDataField() + { + return $this->getViewState('DataField',''); + } + + /** + * @param string the field name from the data source to bind to the column + */ + public function setDataField($value) + { + $this->setViewState('DataField',$value,''); + } + + /** + * @return string the formatting string used to control how the bound data will be displayed. + */ + public function getDataFormatString() + { + return $this->getViewState('DataFormatString',''); + } + + /** + * @param string the formatting string used to control how the bound data will be displayed. + */ + public function setDataFormatString($value) + { + $this->setViewState('DataFormatString',$value,''); + } + + /** + * @return string static text to be displayed in the column. Defaults to empty. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * @param string static text to be displayed in the column. + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * @return boolean whether the rendered text should be HTML-encoded. Defaults to false. + */ + public function getEncode() + { + return $this->getViewState('Encode',false); + } + + /** + * @param boolean whether the rendered text should be HTML-encoded. + */ + public function setEncode($value) + { + $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem) + { + if($this->getDataField()!=='') + $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + else + { + if(($dataField=$this->getDataField())!=='') + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + else + { + $text=$this->getText(); + if($this->getEncode()) + $text=THttpUtility::htmlEncode($text); + $cell->setText($text); + } + } + } + else + parent::initializeCell($cell,$columnIndex,$itemType); + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $data=$item->getData(); + $formatString=$this->getDataFormatString(); + if(($field=$this->getDataField())!=='') + $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field)); + else + $value=$this->formatDataValue($formatString,$data); + if($sender instanceof TTableCell) + { + if($this->getEncode()) + $value=THttpUtility::htmlEncode($value); + $sender->setText($value); + } + } +} + diff --git a/framework/Web/UI/WebControls/TMarkdown.php b/framework/Web/UI/WebControls/TMarkdown.php index 3aa1c9be..726a1ebe 100644 --- a/framework/Web/UI/WebControls/TMarkdown.php +++ b/framework/Web/UI/WebControls/TMarkdown.php @@ -1,75 +1,75 @@ -<?php
-/**
- * TMarkdown class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TMarkdown class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TTextHighlighter and MarkdownParser classes
- */
-Prado::using('System.Web.UI.WebControls.TTextHighlighter');
-Prado::using('System.3rdParty.Markdown.MarkdownParser');
-
-/**
- * TMarkdown class
- *
- * TMarkdown is a control that produces HTML from code with markdown syntax.
- *
- * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
- * you to write using an easy-to-read, easy-to-write plain text format, then
- * convert it to structurally valid XHTML (or HTML).
- * Further documentation regarding Markdown can be found at
- * http://daringfireball.net/projects/markdown/
- *
- * To use TMarkdown, simply enclose the content to be rendered within
- * the body of TMarkdown in a template.
- *
- * See http://www.pradosoft.com/demos/quickstart/?page=Markdown for
- * details on the Markdown syntax usage.
- *
- * TMarkdown also performs syntax highlighting for code blocks whose language
- * is recognized by {@link TTextHighlighter}.
- * The language of a code block must be specified in the first line of the block
- * and enclosed within a pair of square brackets (e.g. [php]).
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TMarkdown extends TTextHighlighter
-{
- /**
- * Processes a text string.
- * This method is required by the parent class.
- * @param string text string to be processed
- * @return string the processed text result
- */
- public function processText($text)
- {
- $renderer = new MarkdownParser;
- $result = $renderer->parse($text);
- return preg_replace_callback(
- '/<pre><code>\[\s*(\w+)\s*\]\n+((.|\n)*?)\s*<\\/code><\\/pre>/im',
- array($this, 'highlightCode'), $result);
- }
-
- /**
- * Highlights source code using TTextHighlighter
- * @param array matches of code blocks
- * @return string highlighted code.
- */
- protected function highlightCode($matches)
- {
- $text = html_entity_decode($matches[2],ENT_QUOTES,'UTF-8');
- $this->setLanguage($matches[1]);
- return parent::processText($text);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TTextHighlighter and MarkdownParser classes + */ +Prado::using('System.Web.UI.WebControls.TTextHighlighter'); +Prado::using('System.3rdParty.Markdown.MarkdownParser'); + +/** + * TMarkdown class + * + * TMarkdown is a control that produces HTML from code with markdown syntax. + * + * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows + * you to write using an easy-to-read, easy-to-write plain text format, then + * convert it to structurally valid XHTML (or HTML). + * Further documentation regarding Markdown can be found at + * http://daringfireball.net/projects/markdown/ + * + * To use TMarkdown, simply enclose the content to be rendered within + * the body of TMarkdown in a template. + * + * See http://www.pradosoft.com/demos/quickstart/?page=Markdown for + * details on the Markdown syntax usage. + * + * TMarkdown also performs syntax highlighting for code blocks whose language + * is recognized by {@link TTextHighlighter}. + * The language of a code block must be specified in the first line of the block + * and enclosed within a pair of square brackets (e.g. [php]). + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.1 + */ +class TMarkdown extends TTextHighlighter +{ + /** + * Processes a text string. + * This method is required by the parent class. + * @param string text string to be processed + * @return string the processed text result + */ + public function processText($text) + { + $renderer = new MarkdownParser; + $result = $renderer->parse($text); + return preg_replace_callback( + '/<pre><code>\[\s*(\w+)\s*\]\n+((.|\n)*?)\s*<\\/code><\\/pre>/im', + array($this, 'highlightCode'), $result); + } + + /** + * Highlights source code using TTextHighlighter + * @param array matches of code blocks + * @return string highlighted code. + */ + protected function highlightCode($matches) + { + $text = html_entity_decode($matches[2],ENT_QUOTES,'UTF-8'); + $this->setLanguage($matches[1]); + return parent::processText($text); + } +} + diff --git a/framework/Web/UI/WebControls/TMultiView.php b/framework/Web/UI/WebControls/TMultiView.php index 81d404b2..0c40cd06 100644 --- a/framework/Web/UI/WebControls/TMultiView.php +++ b/framework/Web/UI/WebControls/TMultiView.php @@ -1,378 +1,378 @@ -<?php
-/**
- * TMultiView and TView class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TMultiView class
- *
- * TMultiView serves as a container for a group of {@link TView} controls.
- * The view collection can be retrieved by {@link getViews Views}.
- * Each view contains child controls. TMultiView determines which view and its
- * child controls are visible. At any time, at most one view is visible (called
- * active). To make a view active, set {@link setActiveView ActiveView} or
- * {@link setActiveViewIndex ActiveViewIndex}.
- *
- * TMultiView also responds to specific command events raised from button controls
- * contained in current active view. A command event with name 'NextView'
- * will cause TMultiView to make the next available view active.
- * Other command names recognized by TMultiView include
- * - PreviousView : switch to previous view
- * - SwitchViewID : switch to a view by its ID path
- * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
- *
- * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
- * when its active view is changed during a postback.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMultiView extends TControl
-{
- const CMD_NEXTVIEW='NextView';
- const CMD_PREVIOUSVIEW='PreviousView';
- const CMD_SWITCHVIEWID='SwitchViewID';
- const CMD_SWITCHVIEWINDEX='SwitchViewIndex';
- private $_cachedActiveViewIndex=-1;
- private $_ignoreBubbleEvents=false;
-
- /**
- * Processes an object that is created during parsing template.
- * This method overrides the parent implementation by adding only {@link TView}
- * controls as children.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- * @throws TConfigurationException if controls other than {@link TView} is being added
- */
- public function addParsedObject($object)
- {
- if($object instanceof TView)
- $this->getControls()->add($object);
- else if(!is_string($object))
- throw new TConfigurationException('multiview_view_required');
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TViewCollection control collection
- */
- protected function createControlCollection()
- {
- return new TViewCollection($this);
- }
-
- /**
- * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1.
- */
- public function getActiveViewIndex()
- {
- if($this->_cachedActiveViewIndex>-1)
- return $this->_cachedActiveViewIndex;
- else
- return $this->getControlState('ActiveViewIndex',-1);
- }
-
- /**
- * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
- * @throws TInvalidDataValueException if the view index is invalid
- */
- public function setActiveViewIndex($value)
- {
- if(($index=TPropertyValue::ensureInteger($value))<0)
- $index=-1;
- $views=$this->getViews();
- $count=$views->getCount();
- if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED)
- $this->_cachedActiveViewIndex=$index;
- else if($index<$count)
- {
- $this->setControlState('ActiveViewIndex',$index,-1);
- $this->_cachedActiveViewIndex=-1;
- if($index>=0)
- $this->activateView($views->itemAt($index),true);
- }
- else
- throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
- }
-
- /**
- * @return TView the currently active view, null if no active view
- * @throws TInvalidDataValueException if the current active view index is invalid
- */
- public function getActiveView()
- {
- $index=$this->getActiveViewIndex();
- $views=$this->getViews();
- if($index>=$views->getCount())
- throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
- if($index<0)
- return null;
- $view=$views->itemAt($index);
- if(!$view->getActive())
- $this->activateView($view,false);
- return $view;
- }
-
- /**
- * @param TView the view to be activated
- * @throws TInvalidOperationException if the view is not in the view collection
- */
- public function setActiveView($view)
- {
- if(($index=$this->getViews()->indexOf($view))>=0)
- $this->setActiveViewIndex($index);
- else
- throw new TInvalidOperationException('multiview_view_inexistent');
- }
-
- /**
- * Activates the specified view.
- * If there is any view currently active, it will be deactivated.
- * @param TView the view to be activated
- * @param boolean whether to trigger OnActiveViewChanged event.
- */
- protected function activateView($view,$triggerViewChangedEvent=true)
- {
- if($view->getActive())
- return;
- $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
- foreach($this->getViews() as $v)
- {
- if($v===$view)
- {
- $view->setActive(true);
- if($triggerEvent)
- {
- $view->onActivate(null);
- $this->onActiveViewChanged(null);
- }
- }
- else if($v->getActive())
- {
- $v->setActive(false);
- if($triggerEvent)
- $v->onDeactivate(null);
- }
- }
- }
-
- /**
- * @return TViewCollection the view collection
- */
- public function getViews()
- {
- return $this->getControls();
- }
-
- /**
- * Makes the multiview ignore all bubbled events.
- * This is method is used internally by framework and control
- * developers.
- */
- public function ignoreBubbleEvents()
- {
- $this->_ignoreBubbleEvents=true;
- }
-
- /**
- * Initializes the active view if any.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- if($this->_cachedActiveViewIndex>=0)
- $this->setActiveViewIndex($this->_cachedActiveViewIndex);
- }
-
- /**
- * Raises <b>OnActiveViewChanged</b> event.
- * The event is raised when the currently active view is changed to a new one
- * @param TEventParameter event parameter
- */
- public function onActiveViewChanged($param)
- {
- $this->raiseEvent('OnActiveViewChanged',$this,$param);
- }
-
- /**
- * Processes the events bubbled from child controls.
- * The method handles view-related command events.
- * @param TControl sender of the event
- * @param mixed event parameter
- * @return boolean whether this event is handled
- */
- public function bubbleEvent($sender,$param)
- {
- if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter))
- {
- switch($param->getCommandName())
- {
- case self::CMD_NEXTVIEW:
- if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1)
- $this->setActiveViewIndex($index+1);
- else
- $this->setActiveViewIndex(-1);
- return true;
- case self::CMD_PREVIOUSVIEW:
- if(($index=$this->getActiveViewIndex())>=0)
- $this->setActiveViewIndex($index-1);
- return true;
- case self::CMD_SWITCHVIEWID:
- $view=$this->findControl($viewID=$param->getCommandParameter());
- if($view!==null && $view->getParent()===$this)
- {
- $this->setActiveView($view);
- return true;
- }
- else
- throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID);
- case self::CMD_SWITCHVIEWINDEX:
- $index=TPropertyValue::ensureInteger($param->getCommandParameter());
- $this->setActiveViewIndex($index);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Loads state into the wizard.
- * This method is invoked by the framework when the control state is being saved.
- */
- public function loadState()
- {
- // a dummy call to ensure the view is activated
- $this->getActiveView();
- }
-
- /**
- * Renders the currently active view.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function render($writer)
- {
- if(($view=$this->getActiveView())!==null)
- $view->renderControl($writer);
- }
-}
-
-/**
- * TViewCollection class.
- * TViewCollection represents a collection that only takes {@link TView} instances
- * as collection elements.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TViewCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by ensuring only {@link TView}
- * controls be added into the collection.
- * @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 TView)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('viewcollection_view_required');
- }
-}
-
-/**
- * TView class
- *
- * TView is a container for a group of controls. TView must be contained
- * within a {@link TMultiView} control in which only one view can be active
- * at one time.
- *
- * To activate a view, set {@link setActive Active} to true.
- * When a view is activated, it raises {@link onActivate OnActivate} event;
- * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TView extends TControl
-{
- private $_active=false;
-
- /**
- * Raises <b>OnActivate</b> event.
- * @param TEventParameter event parameter
- */
- public function onActivate($param)
- {
- $this->raiseEvent('OnActivate',$this,$param);
- }
-
- /**
- * Raises <b>OnDeactivate</b> event.
- * @param TEventParameter event parameter
- */
- public function onDeactivate($param)
- {
- $this->raiseEvent('OnDeactivate',$this,$param);
- }
-
- /**
- * @return boolean whether this view is active. Defaults to false.
- */
- public function getActive()
- {
- return $this->_active;
- }
-
- /**
- * @param boolean whether this view is active.
- */
- public function setActive($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- $this->_active=$value;
- parent::setVisible($value);
- }
-
- /**
- * @param boolean whether the parents should also be checked if visible
- * @return boolean whether this view is visible.
- * The view is visible if it is active and its parent is visible.
- */
- public function getVisible($checkParents=true)
- {
- if(($parent=$this->getParent())===null)
- return $this->getActive();
- else if($this->getActive())
- return $parent->getVisible($checkParents);
- else
- return false;
- }
-
- /**
- * @param boolean
- * @throws TInvalidOperationException whenever this method is invoked.
- */
- public function setVisible($value)
- {
- throw new TInvalidOperationException('view_visible_readonly');
- }
-}
-
+<?php +/** + * TMultiView and TView class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TMultiView class + * + * TMultiView serves as a container for a group of {@link TView} controls. + * The view collection can be retrieved by {@link getViews Views}. + * Each view contains child controls. TMultiView determines which view and its + * child controls are visible. At any time, at most one view is visible (called + * active). To make a view active, set {@link setActiveView ActiveView} or + * {@link setActiveViewIndex ActiveViewIndex}. + * + * TMultiView also responds to specific command events raised from button controls + * contained in current active view. A command event with name 'NextView' + * will cause TMultiView to make the next available view active. + * Other command names recognized by TMultiView include + * - PreviousView : switch to previous view + * - SwitchViewID : switch to a view by its ID path + * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection. + * + * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event + * when its active view is changed during a postback. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TMultiView extends TControl +{ + const CMD_NEXTVIEW='NextView'; + const CMD_PREVIOUSVIEW='PreviousView'; + const CMD_SWITCHVIEWID='SwitchViewID'; + const CMD_SWITCHVIEWINDEX='SwitchViewIndex'; + private $_cachedActiveViewIndex=-1; + private $_ignoreBubbleEvents=false; + + /** + * Processes an object that is created during parsing template. + * This method overrides the parent implementation by adding only {@link TView} + * controls as children. + * @param string|TComponent text string or component parsed and instantiated in template + * @see createdOnTemplate + * @throws TConfigurationException if controls other than {@link TView} is being added + */ + public function addParsedObject($object) + { + if($object instanceof TView) + $this->getControls()->add($object); + else if(!is_string($object)) + throw new TConfigurationException('multiview_view_required'); + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TViewCollection control collection + */ + protected function createControlCollection() + { + return new TViewCollection($this); + } + + /** + * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1. + */ + public function getActiveViewIndex() + { + if($this->_cachedActiveViewIndex>-1) + return $this->_cachedActiveViewIndex; + else + return $this->getControlState('ActiveViewIndex',-1); + } + + /** + * @param integer the zero-based index of the current view in the view collection. -1 if no active view. + * @throws TInvalidDataValueException if the view index is invalid + */ + public function setActiveViewIndex($value) + { + if(($index=TPropertyValue::ensureInteger($value))<0) + $index=-1; + $views=$this->getViews(); + $count=$views->getCount(); + if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED) + $this->_cachedActiveViewIndex=$index; + else if($index<$count) + { + $this->setControlState('ActiveViewIndex',$index,-1); + $this->_cachedActiveViewIndex=-1; + if($index>=0) + $this->activateView($views->itemAt($index),true); + } + else + throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index); + } + + /** + * @return TView the currently active view, null if no active view + * @throws TInvalidDataValueException if the current active view index is invalid + */ + public function getActiveView() + { + $index=$this->getActiveViewIndex(); + $views=$this->getViews(); + if($index>=$views->getCount()) + throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index); + if($index<0) + return null; + $view=$views->itemAt($index); + if(!$view->getActive()) + $this->activateView($view,false); + return $view; + } + + /** + * @param TView the view to be activated + * @throws TInvalidOperationException if the view is not in the view collection + */ + public function setActiveView($view) + { + if(($index=$this->getViews()->indexOf($view))>=0) + $this->setActiveViewIndex($index); + else + throw new TInvalidOperationException('multiview_view_inexistent'); + } + + /** + * Activates the specified view. + * If there is any view currently active, it will be deactivated. + * @param TView the view to be activated + * @param boolean whether to trigger OnActiveViewChanged event. + */ + protected function activateView($view,$triggerViewChangedEvent=true) + { + if($view->getActive()) + return; + $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack())); + foreach($this->getViews() as $v) + { + if($v===$view) + { + $view->setActive(true); + if($triggerEvent) + { + $view->onActivate(null); + $this->onActiveViewChanged(null); + } + } + else if($v->getActive()) + { + $v->setActive(false); + if($triggerEvent) + $v->onDeactivate(null); + } + } + } + + /** + * @return TViewCollection the view collection + */ + public function getViews() + { + return $this->getControls(); + } + + /** + * Makes the multiview ignore all bubbled events. + * This is method is used internally by framework and control + * developers. + */ + public function ignoreBubbleEvents() + { + $this->_ignoreBubbleEvents=true; + } + + /** + * Initializes the active view if any. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onInit($param) + { + parent::onInit($param); + if($this->_cachedActiveViewIndex>=0) + $this->setActiveViewIndex($this->_cachedActiveViewIndex); + } + + /** + * Raises <b>OnActiveViewChanged</b> event. + * The event is raised when the currently active view is changed to a new one + * @param TEventParameter event parameter + */ + public function onActiveViewChanged($param) + { + $this->raiseEvent('OnActiveViewChanged',$this,$param); + } + + /** + * Processes the events bubbled from child controls. + * The method handles view-related command events. + * @param TControl sender of the event + * @param mixed event parameter + * @return boolean whether this event is handled + */ + public function bubbleEvent($sender,$param) + { + if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter)) + { + switch($param->getCommandName()) + { + case self::CMD_NEXTVIEW: + if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1) + $this->setActiveViewIndex($index+1); + else + $this->setActiveViewIndex(-1); + return true; + case self::CMD_PREVIOUSVIEW: + if(($index=$this->getActiveViewIndex())>=0) + $this->setActiveViewIndex($index-1); + return true; + case self::CMD_SWITCHVIEWID: + $view=$this->findControl($viewID=$param->getCommandParameter()); + if($view!==null && $view->getParent()===$this) + { + $this->setActiveView($view); + return true; + } + else + throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID); + case self::CMD_SWITCHVIEWINDEX: + $index=TPropertyValue::ensureInteger($param->getCommandParameter()); + $this->setActiveViewIndex($index); + return true; + } + } + return false; + } + + /** + * Loads state into the wizard. + * This method is invoked by the framework when the control state is being saved. + */ + public function loadState() + { + // a dummy call to ensure the view is activated + $this->getActiveView(); + } + + /** + * Renders the currently active view. + * @param THtmlWriter the writer for the rendering purpose. + */ + public function render($writer) + { + if(($view=$this->getActiveView())!==null) + $view->renderControl($writer); + } +} + +/** + * TViewCollection class. + * TViewCollection represents a collection that only takes {@link TView} instances + * as collection elements. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TViewCollection extends TControlCollection +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by ensuring only {@link TView} + * controls be added into the collection. + * @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 TView) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('viewcollection_view_required'); + } +} + +/** + * TView class + * + * TView is a container for a group of controls. TView must be contained + * within a {@link TMultiView} control in which only one view can be active + * at one time. + * + * To activate a view, set {@link setActive Active} to true. + * When a view is activated, it raises {@link onActivate OnActivate} event; + * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TView extends TControl +{ + private $_active=false; + + /** + * Raises <b>OnActivate</b> event. + * @param TEventParameter event parameter + */ + public function onActivate($param) + { + $this->raiseEvent('OnActivate',$this,$param); + } + + /** + * Raises <b>OnDeactivate</b> event. + * @param TEventParameter event parameter + */ + public function onDeactivate($param) + { + $this->raiseEvent('OnDeactivate',$this,$param); + } + + /** + * @return boolean whether this view is active. Defaults to false. + */ + public function getActive() + { + return $this->_active; + } + + /** + * @param boolean whether this view is active. + */ + public function setActive($value) + { + $value=TPropertyValue::ensureBoolean($value); + $this->_active=$value; + parent::setVisible($value); + } + + /** + * @param boolean whether the parents should also be checked if visible + * @return boolean whether this view is visible. + * The view is visible if it is active and its parent is visible. + */ + public function getVisible($checkParents=true) + { + if(($parent=$this->getParent())===null) + return $this->getActive(); + else if($this->getActive()) + return $parent->getVisible($checkParents); + else + return false; + } + + /** + * @param boolean + * @throws TInvalidOperationException whenever this method is invoked. + */ + public function setVisible($value) + { + throw new TInvalidOperationException('view_visible_readonly'); + } +} + diff --git a/framework/Web/UI/WebControls/TOutputCache.php b/framework/Web/UI/WebControls/TOutputCache.php index 64e4ff42..cc79e76f 100644 --- a/framework/Web/UI/WebControls/TOutputCache.php +++ b/framework/Web/UI/WebControls/TOutputCache.php @@ -1,621 +1,621 @@ -<?php
-/**
- * TOutputCache class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TOutputCache class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TOutputCache class.
- *
- * TOutputCache enables caching a portion of a Web page, also known as
- * partial caching. The content being cached can be either static or
- * dynamic.
- *
- * To use TOutputCache, simply enclose the content to be cached
- * within the TOutputCache component tag on a template, e.g.,
- * <code>
- * <com:TOutputCache>
- * content to be cached
- * </com:TOutputCache>
- * </code>
- * where content to be cached can be static text and/or component tags.
- *
- * The validity of the cached content is determined based on two factors:
- * the {@link setDuration Duration} and the cache dependency.
- * The former specifies the number of seconds that the data can remain
- * valid in cache (defaults to 60s), while the latter specifies conditions
- * that the cached data depends on. If a dependency changes,
- * (e.g. relevant data in DB are updated), the cached data will be invalidated.
- *
- * There are two ways to specify cache dependency. One may write event handlers
- * to respond to the {@link onCheckDependency OnCheckDependency} event and set
- * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
- * property to indicate whether the cached data remains valid or not.
- * One can also extend TOutputCache and override its {@link getCacheDependency}
- * function. While the former is easier to use, the latter offers more extensibility.
- *
- * The content fetched from cache may be variated with respect to
- * some parameters. It supports variation with respect to request parameters,
- * which is specified by {@link setVaryByParam VaryByParam} property.
- * If a specified request parameter is different, a different version of
- * cached content is used. This is extremely useful if a page's content
- * may be variated according to some GET parameters.
- * The content being cached may also be variated with user sessions if
- * {@link setVaryBySession VaryBySession} is set true.
- * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
- *
- * Output caches can be nested. An outer cache takes precedence over an
- * inner cache. This means, if the content cached by the inner cache expires
- * or is invalidated, while that by the outer cache not, the outer cached
- * content will be used.
- *
- * Note, TOutputCache is effective only for non-postback page requests
- * and when cache module is enabled.
- *
- * Do not attempt to address child controls of TOutputCache when the cached
- * content is to be used. Use {@link getContentCached ContentCached} property
- * to determine whether the content is cached or not.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TOutputCache extends TControl implements INamingContainer
-{
- const CACHE_ID_PREFIX='prado:outputcache';
- private $_cacheModuleID='';
- private $_dataCached=false;
- private $_cacheAvailable=false;
- private $_cacheChecked=false;
- private $_cacheKey=null;
- private $_duration=60;
- private $_cache=null;
- private $_contents;
- private $_state;
- private $_actions=array();
- private $_varyByParam='';
- private $_keyPrefix='';
- private $_varyBySession=false;
- private $_cachePostBack=false;
- private $_cacheTime=0;
-
- /**
- * Returns a value indicating whether body contents are allowed for this control.
- * This method overrides the parent implementation by checking if cached
- * content is available or not. If yes, it returns false, otherwise true.
- * @param boolean whether body contents are allowed for this control.
- */
- public function getAllowChildControls()
- {
- $this->determineCacheability();
- return !$this->_dataCached;
- }
-
- private function determineCacheability()
- {
- if(!$this->_cacheChecked)
- {
- $this->_cacheChecked=true;
- if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
- {
- if($this->_cacheModuleID!=='')
- {
- $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
- if(!($this->_cache instanceof ICache))
- throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
- }
- else
- $this->_cache=$this->getApplication()->getCache();
- if($this->_cache!==null)
- {
- $this->_cacheAvailable=true;
- $data=$this->_cache->get($this->getCacheKey());
- if(is_array($data))
- {
- $param=new TOutputCacheCheckDependencyEventParameter;
- $param->setCacheTime(isset($data[3])?$data[3]:0);
- $this->onCheckDependency($param);
- $this->_dataCached=$param->getIsValid();
- }
- else
- $this->_dataCached=false;
- if($this->_dataCached)
- list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
- }
- }
- }
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::initRecursive($namingContainer);
- $stack->pop();
- }
- else
- parent::initRecursive($namingContainer);
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page. If the data is restored
- * from cache, it also recovers the actions associated with the cached data.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function loadRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::loadRecursive();
- $stack->pop();
- }
- else
- {
- if($this->_dataCached)
- $this->performActions();
- parent::loadRecursive();
- }
- }
-
- private function performActions()
- {
- $page=$this->getPage();
- $cs=$page->getClientScript();
- foreach($this->_actions as $action)
- {
- if($action[0]==='Page.ClientScript')
- call_user_func_array(array($cs,$action[1]),$action[2]);
- else if($action[0]==='Page')
- call_user_func_array(array($page,$action[1]),$action[2]);
- else
- call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
- }
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function preRenderRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::preRenderRecursive();
- $stack->pop();
- }
- else
- parent::preRenderRecursive();
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method overrides the parent implementation by loading
- * cached state if available.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- $st=unserialize($state);
- parent::loadStateRecursive($st,$needViewState);
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method overrides the parent implementation by saving state
- * into cache if needed.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if($this->_dataCached)
- return $this->_state;
- else
- {
- $st=parent::saveStateRecursive($needViewState);
- // serialization is needed to avoid undefined classes when loading state
- $this->_state=serialize($st);
- return $this->_state;
- }
- }
-
- /**
- * 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 registerAction($context,$funcName,$funcParams)
- {
- $this->_actions[]=array($context,$funcName,$funcParams);
- }
-
- public function getCacheKey()
- {
- if($this->_cacheKey===null)
- $this->_cacheKey=$this->calculateCacheKey();
- return $this->_cacheKey;
- }
-
- /**
- * Calculates the cache key.
- * The key is calculated based on the unique ID of this control
- * and the request parameters specified via {@link setVaryByParam VaryByParam}.
- * If {@link getVaryBySession VaryBySession} is true, the session ID
- * will also participate in the key calculation.
- * This method may be overriden to support other variations in
- * the calculated cache key.
- * @return string cache key
- */
- protected function calculateCacheKey()
- {
- $key=$this->getBaseCacheKey();
- if($this->_varyBySession)
- $key.=$this->getSession()->getSessionID();
- if($this->_varyByParam!=='')
- {
- $params=array();
- $request=$this->getRequest();
- foreach(explode(',',$this->_varyByParam) as $name)
- {
- $name=trim($name);
- $params[$name]=$request->itemAt($name);
- }
- $key.=serialize($params);
- }
- $param=new TOutputCacheCalculateKeyEventParameter;
- $this->onCalculateKey($param);
- $key.=$param->getCacheKey();
- return $key;
- }
-
- /**
- * @return string basic cache key without variations
- */
- protected function getBaseCacheKey()
- {
- return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
- }
-
- /**
- * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If empty, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * Sets the prefix of the cache key.
- * This method is used internally by {@link TTemplate}.
- * @param string key prefix
- */
- public function setCacheKeyPrefix($value)
- {
- $this->_keyPrefix=$value;
- }
-
- /**
- * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * Returns the dependency of the data to be cached.
- * The default implementation simply returns null, meaning no specific dependency.
- * This method may be overriden to associate the data to be cached
- * with additional dependencies.
- * @return ICacheDependency
- */
- protected function getCacheDependency()
- {
- return null;
- }
-
- /**
- * @return boolean whether content enclosed is cached or not
- */
- public function getContentCached()
- {
- return $this->_dataCached;
- }
-
- /**
- * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
- * Note, if cache dependency changes or cache space is limited,
- * the data may be purged out of cache earlier.
- */
- public function getDuration()
- {
- return $this->_duration;
- }
-
- /**
- * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
- * @throws TInvalidDataValueException if the value is smaller than 0.
- */
- public function setDuration($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
- $this->_duration=$value;
- }
-
- /**
- * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
- */
- public function getVaryByParam()
- {
- return $this->_varyByParam;
- }
-
- /**
- * Sets the names of the request parameters that should be used in calculating the cache key.
- * The names should be concatenated by semicolons.
- * By setting this value, the output cache will use different cached data
- * for each different set of request parameter values.
- * @return string a semicolon-separated list of strings used to vary the output cache.
- */
- public function setVaryByParam($value)
- {
- $this->_varyByParam=trim($value);
- }
-
- /**
- * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
- */
- public function getVaryBySession()
- {
- return $this->_varyBySession;
- }
-
- /**
- * @param boolean whether the content being cached should be differentiated according to user sessions.
- */
- public function setVaryBySession($value)
- {
- $this->_varyBySession=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether cached output will be used on postback requests. Defaults to false.
- */
- public function getCachingPostBack()
- {
- return $this->_cachePostBack;
- }
-
- /**
- * Sets a value indicating whether cached output will be used on postback requests.
- * By default, this is disabled. Be very cautious when enabling it.
- * If the cached content including interactive user controls such as
- * TTextBox, TDropDownList, your page may fail to render on postbacks.
- * @param boolean whether cached output will be used on postback requests.
- */
- public function setCachingPostBack($value)
- {
- $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * This event is raised when the output cache is checking cache dependency.
- * An event handler may be written to check customized dependency conditions.
- * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
- * property of the event parameter (which defaults to true).
- * @param TOutputCacheCheckDependencyEventParameter event parameter
- */
- public function onCheckDependency($param)
- {
- $this->raiseEvent('OnCheckDependency',$this,$param);
- }
-
- /**
- * This event is raised when the output cache is calculating cache key.
- * By varying cache keys, one can obtain different versions of cached content.
- * An event handler may be written to add variety of the key calculation.
- * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
- * this event parameter will be appended to the default key calculation scheme.
- * @param TOutputCacheCalculateKeyEventParameter event parameter
- */
- public function onCalculateKey($param)
- {
- $this->raiseEvent('OnCalculateKey',$this,$param);
- }
-
- /**
- * Renders the output cache control.
- * This method overrides the parent implementation by capturing the output
- * from its child controls and saving it into cache, if output cache is needed.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- if($this->_dataCached)
- $writer->write($this->_contents);
- else if($this->_cacheAvailable)
- {
- $textwriter = new TTextWriter();
- $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
-
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::render($htmlWriter);
- $stack->pop();
-
- $content=$textwriter->flush();
- $data=array($content,$this->_state,$this->_actions,time());
- $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
- }
- else
- parent::render($writer);
- }
-}
-
-/**
- * TOutputCacheCheckDependencyEventParameter class
- *
- * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
- * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCheckDependencyEventParameter extends TEventParameter
-{
- private $_isValid=true;
- private $_cacheTime=0;
-
- /**
- * @return boolean whether the dependency remains valid. Defaults to true.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the dependency remains valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * @param integer the timestamp of the cached result. This is used internally.
- * @since 3.1.1
- */
- public function setCacheTime($value)
- {
- $this->_cacheTime=TPropertyValue::ensureInteger($value);
- }
-}
-
-
-/**
- * TOutputCacheCalculateKeyEventParameter class
- *
- * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
- * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCalculateKeyEventParameter extends TEventParameter
-{
- /**
- * @var string cache key to be appended to the default calculation scheme.
- */
- private $_cacheKey='';
-
- /**
- * @return string cache key to be appended to the default calculation scheme.
- */
- public function getCacheKey()
- {
- return $this->_cacheKey;
- }
-
- /**
- * @param string cache key to be appended to the default calculation scheme
- */
- public function setCacheKey($value)
- {
- $this->_cacheKey=TPropertyValue::ensureString($value);
- }
-}
-
-/**
- * TOutputCacheTextWriterMulti class
- *
- * TOutputCacheTextWriterMulti is an internal class used by
- * TOutputCache to write simultaneously to multiple writers.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TOutputCacheTextWriterMulti extends TTextWriter
-{
- protected $_writers;
-
- public function __construct(Array $writers)
- {
- //parent::__construct();
- $this->_writers = $writers;
- }
-
- public function write($s)
- {
- foreach($this->_writers as $writer)
- $writer->write($s);
- }
-
- public function flush()
- {
- foreach($this->_writers as $writer)
- $s = $writer->flush();
- return $s;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TOutputCache class. + * + * TOutputCache enables caching a portion of a Web page, also known as + * partial caching. The content being cached can be either static or + * dynamic. + * + * To use TOutputCache, simply enclose the content to be cached + * within the TOutputCache component tag on a template, e.g., + * <code> + * <com:TOutputCache> + * content to be cached + * </com:TOutputCache> + * </code> + * where content to be cached can be static text and/or component tags. + * + * The validity of the cached content is determined based on two factors: + * the {@link setDuration Duration} and the cache dependency. + * The former specifies the number of seconds that the data can remain + * valid in cache (defaults to 60s), while the latter specifies conditions + * that the cached data depends on. If a dependency changes, + * (e.g. relevant data in DB are updated), the cached data will be invalidated. + * + * There are two ways to specify cache dependency. One may write event handlers + * to respond to the {@link onCheckDependency OnCheckDependency} event and set + * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid} + * property to indicate whether the cached data remains valid or not. + * One can also extend TOutputCache and override its {@link getCacheDependency} + * function. While the former is easier to use, the latter offers more extensibility. + * + * The content fetched from cache may be variated with respect to + * some parameters. It supports variation with respect to request parameters, + * which is specified by {@link setVaryByParam VaryByParam} property. + * If a specified request parameter is different, a different version of + * cached content is used. This is extremely useful if a page's content + * may be variated according to some GET parameters. + * The content being cached may also be variated with user sessions if + * {@link setVaryBySession VaryBySession} is set true. + * To variate the cached content by other factors, override {@link calculateCacheKey()} method. + * + * Output caches can be nested. An outer cache takes precedence over an + * inner cache. This means, if the content cached by the inner cache expires + * or is invalidated, while that by the outer cache not, the outer cached + * content will be used. + * + * Note, TOutputCache is effective only for non-postback page requests + * and when cache module is enabled. + * + * Do not attempt to address child controls of TOutputCache when the cached + * content is to be used. Use {@link getContentCached ContentCached} property + * to determine whether the content is cached or not. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1 + */ +class TOutputCache extends TControl implements INamingContainer +{ + const CACHE_ID_PREFIX='prado:outputcache'; + private $_cacheModuleID=''; + private $_dataCached=false; + private $_cacheAvailable=false; + private $_cacheChecked=false; + private $_cacheKey=null; + private $_duration=60; + private $_cache=null; + private $_contents; + private $_state; + private $_actions=array(); + private $_varyByParam=''; + private $_keyPrefix=''; + private $_varyBySession=false; + private $_cachePostBack=false; + private $_cacheTime=0; + + /** + * Returns a value indicating whether body contents are allowed for this control. + * This method overrides the parent implementation by checking if cached + * content is available or not. If yes, it returns false, otherwise true. + * @param boolean whether body contents are allowed for this control. + */ + public function getAllowChildControls() + { + $this->determineCacheability(); + return !$this->_dataCached; + } + + private function determineCacheability() + { + if(!$this->_cacheChecked) + { + $this->_cacheChecked=true; + if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack())) + { + if($this->_cacheModuleID!=='') + { + $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID); + if(!($this->_cache instanceof ICache)) + throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID); + } + else + $this->_cache=$this->getApplication()->getCache(); + if($this->_cache!==null) + { + $this->_cacheAvailable=true; + $data=$this->_cache->get($this->getCacheKey()); + if(is_array($data)) + { + $param=new TOutputCacheCheckDependencyEventParameter; + $param->setCacheTime(isset($data[3])?$data[3]:0); + $this->onCheckDependency($param); + $this->_dataCached=$param->getIsValid(); + } + else + $this->_dataCached=false; + if($this->_dataCached) + list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data; + } + } + } + } + + /** + * Performs the Init step for the control and all its child controls. + * This method overrides the parent implementation by setting up + * the stack of the output cache in the page. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function initRecursive($namingContainer=null) + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::initRecursive($namingContainer); + $stack->pop(); + } + else + parent::initRecursive($namingContainer); + } + + /** + * Performs the Load step for the control and all its child controls. + * This method overrides the parent implementation by setting up + * the stack of the output cache in the page. If the data is restored + * from cache, it also recovers the actions associated with the cached data. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function loadRecursive() + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::loadRecursive(); + $stack->pop(); + } + else + { + if($this->_dataCached) + $this->performActions(); + parent::loadRecursive(); + } + } + + private function performActions() + { + $page=$this->getPage(); + $cs=$page->getClientScript(); + foreach($this->_actions as $action) + { + if($action[0]==='Page.ClientScript') + call_user_func_array(array($cs,$action[1]),$action[2]); + else if($action[0]==='Page') + call_user_func_array(array($page,$action[1]),$action[2]); + else + call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]); + } + } + + /** + * Performs the PreRender step for the control and all its child controls. + * This method overrides the parent implementation by setting up + * the stack of the output cache in the page. + * Only framework developers should use this method. + * @param TControl the naming container control + */ + protected function preRenderRecursive() + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::preRenderRecursive(); + $stack->pop(); + } + else + parent::preRenderRecursive(); + } + + /** + * Loads state (viewstate and controlstate) into a control and its children. + * This method overrides the parent implementation by loading + * cached state if available. + * This method should only be used by framework developers. + * @param array the collection of the state + * @param boolean whether the viewstate should be loaded + */ + protected function loadStateRecursive(&$state,$needViewState=true) + { + $st=unserialize($state); + parent::loadStateRecursive($st,$needViewState); + } + + /** + * Saves all control state (viewstate and controlstate) as a collection. + * This method overrides the parent implementation by saving state + * into cache if needed. + * This method should only be used by framework developers. + * @param boolean whether the viewstate should be saved + * @return array the collection of the control state (including its children's state). + */ + protected function &saveStateRecursive($needViewState=true) + { + if($this->_dataCached) + return $this->_state; + else + { + $st=parent::saveStateRecursive($needViewState); + // serialization is needed to avoid undefined classes when loading state + $this->_state=serialize($st); + return $this->_state; + } + } + + /** + * 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 registerAction($context,$funcName,$funcParams) + { + $this->_actions[]=array($context,$funcName,$funcParams); + } + + public function getCacheKey() + { + if($this->_cacheKey===null) + $this->_cacheKey=$this->calculateCacheKey(); + return $this->_cacheKey; + } + + /** + * Calculates the cache key. + * The key is calculated based on the unique ID of this control + * and the request parameters specified via {@link setVaryByParam VaryByParam}. + * If {@link getVaryBySession VaryBySession} is true, the session ID + * will also participate in the key calculation. + * This method may be overriden to support other variations in + * the calculated cache key. + * @return string cache key + */ + protected function calculateCacheKey() + { + $key=$this->getBaseCacheKey(); + if($this->_varyBySession) + $key.=$this->getSession()->getSessionID(); + if($this->_varyByParam!=='') + { + $params=array(); + $request=$this->getRequest(); + foreach(explode(',',$this->_varyByParam) as $name) + { + $name=trim($name); + $params[$name]=$request->itemAt($name); + } + $key.=serialize($params); + } + $param=new TOutputCacheCalculateKeyEventParameter; + $this->onCalculateKey($param); + $key.=$param->getCacheKey(); + return $key; + } + + /** + * @return string basic cache key without variations + */ + protected function getBaseCacheKey() + { + return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID(); + } + + /** + * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used. + */ + public function getCacheModuleID() + { + return $this->_cacheModuleID; + } + + /** + * @param string the ID of the cache module. If empty, the primary cache module will be used. + */ + public function setCacheModuleID($value) + { + $this->_cacheModuleID=$value; + } + + /** + * Sets the prefix of the cache key. + * This method is used internally by {@link TTemplate}. + * @param string key prefix + */ + public function setCacheKeyPrefix($value) + { + $this->_keyPrefix=$value; + } + + /** + * @return integer the timestamp of the cached content. This is only valid if the content is being cached. + * @since 3.1.1 + */ + public function getCacheTime() + { + return $this->_cacheTime; + } + + /** + * Returns the dependency of the data to be cached. + * The default implementation simply returns null, meaning no specific dependency. + * This method may be overriden to associate the data to be cached + * with additional dependencies. + * @return ICacheDependency + */ + protected function getCacheDependency() + { + return null; + } + + /** + * @return boolean whether content enclosed is cached or not + */ + public function getContentCached() + { + return $this->_dataCached; + } + + /** + * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds. + * Note, if cache dependency changes or cache space is limited, + * the data may be purged out of cache earlier. + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached. + * @throws TInvalidDataValueException if the value is smaller than 0. + */ + public function setDuration($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this)); + $this->_duration=$value; + } + + /** + * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''. + */ + public function getVaryByParam() + { + return $this->_varyByParam; + } + + /** + * Sets the names of the request parameters that should be used in calculating the cache key. + * The names should be concatenated by semicolons. + * By setting this value, the output cache will use different cached data + * for each different set of request parameter values. + * @return string a semicolon-separated list of strings used to vary the output cache. + */ + public function setVaryByParam($value) + { + $this->_varyByParam=trim($value); + } + + /** + * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false. + */ + public function getVaryBySession() + { + return $this->_varyBySession; + } + + /** + * @param boolean whether the content being cached should be differentiated according to user sessions. + */ + public function setVaryBySession($value) + { + $this->_varyBySession=TPropertyValue::ensureBoolean($value); + } + + /** + * @return boolean whether cached output will be used on postback requests. Defaults to false. + */ + public function getCachingPostBack() + { + return $this->_cachePostBack; + } + + /** + * Sets a value indicating whether cached output will be used on postback requests. + * By default, this is disabled. Be very cautious when enabling it. + * If the cached content including interactive user controls such as + * TTextBox, TDropDownList, your page may fail to render on postbacks. + * @param boolean whether cached output will be used on postback requests. + */ + public function setCachingPostBack($value) + { + $this->_cachePostBack=TPropertyValue::ensureBoolean($value); + } + + /** + * This event is raised when the output cache is checking cache dependency. + * An event handler may be written to check customized dependency conditions. + * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid} + * property of the event parameter (which defaults to true). + * @param TOutputCacheCheckDependencyEventParameter event parameter + */ + public function onCheckDependency($param) + { + $this->raiseEvent('OnCheckDependency',$this,$param); + } + + /** + * This event is raised when the output cache is calculating cache key. + * By varying cache keys, one can obtain different versions of cached content. + * An event handler may be written to add variety of the key calculation. + * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of + * this event parameter will be appended to the default key calculation scheme. + * @param TOutputCacheCalculateKeyEventParameter event parameter + */ + public function onCalculateKey($param) + { + $this->raiseEvent('OnCalculateKey',$this,$param); + } + + /** + * Renders the output cache control. + * This method overrides the parent implementation by capturing the output + * from its child controls and saving it into cache, if output cache is needed. + * @param THtmlWriter + */ + public function render($writer) + { + if($this->_dataCached) + $writer->write($this->_contents); + else if($this->_cacheAvailable) + { + $textwriter = new TTextWriter(); + $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter)); + $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter); + + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::render($htmlWriter); + $stack->pop(); + + $content=$textwriter->flush(); + $data=array($content,$this->_state,$this->_actions,time()); + $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency()); + } + else + parent::render($writer); + } +} + +/** + * TOutputCacheCheckDependencyEventParameter class + * + * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for + * <b>OnCheckDependency</b> event of {@link TOutputCache} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TOutputCacheCheckDependencyEventParameter extends TEventParameter +{ + private $_isValid=true; + private $_cacheTime=0; + + /** + * @return boolean whether the dependency remains valid. Defaults to true. + */ + public function getIsValid() + { + return $this->_isValid; + } + + /** + * @param boolean whether the dependency remains valid + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + + /** + * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed. + * @since 3.1.1 + */ + public function getCacheTime() + { + return $this->_cacheTime; + } + + /** + * @param integer the timestamp of the cached result. This is used internally. + * @since 3.1.1 + */ + public function setCacheTime($value) + { + $this->_cacheTime=TPropertyValue::ensureInteger($value); + } +} + + +/** + * TOutputCacheCalculateKeyEventParameter class + * + * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for + * <b>OnCalculateKey</b> event of {@link TOutputCache} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TOutputCacheCalculateKeyEventParameter extends TEventParameter +{ + /** + * @var string cache key to be appended to the default calculation scheme. + */ + private $_cacheKey=''; + + /** + * @return string cache key to be appended to the default calculation scheme. + */ + public function getCacheKey() + { + return $this->_cacheKey; + } + + /** + * @param string cache key to be appended to the default calculation scheme + */ + public function setCacheKey($value) + { + $this->_cacheKey=TPropertyValue::ensureString($value); + } +} + +/** + * TOutputCacheTextWriterMulti class + * + * TOutputCacheTextWriterMulti is an internal class used by + * TOutputCache to write simultaneously to multiple writers. + * + * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu> + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TOutputCacheTextWriterMulti extends TTextWriter +{ + protected $_writers; + + public function __construct(Array $writers) + { + //parent::__construct(); + $this->_writers = $writers; + } + + public function write($s) + { + foreach($this->_writers as $writer) + $writer->write($s); + } + + public function flush() + { + foreach($this->_writers as $writer) + $s = $writer->flush(); + return $s; + } +} + diff --git a/framework/Web/UI/WebControls/TPager.php b/framework/Web/UI/WebControls/TPager.php index 8e4bf2b0..11de5233 100644 --- a/framework/Web/UI/WebControls/TPager.php +++ b/framework/Web/UI/WebControls/TPager.php @@ -1,792 +1,792 @@ -<?php
-/**
- * TPager class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TPager class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TPager class.
- *
- * TPager creates a pager that provides UI for end-users to interactively
- * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control,
- * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc.
- * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate},
- * which must be the ID path of the target control reaching from the pager's
- * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging}
- * set to true.
- *
- * TPager can display three different UIs, specified via {@link setMode Mode}:
- * - NextPrev: a next page and a previous page button are rendered.
- * - Numeric: a list of page index buttons are rendered.
- * - List: a dropdown list of page indices are rendered.
- *
- * When the pager mode is either NextPrev or Numeric, the paging buttons may be displayed
- * in three types by setting {@link setButtonType ButtonType}:
- * - LinkButton: a hyperlink button
- * - PushButton: a normal button
- * - ImageButton: an image button (please set XXXPageImageUrl properties accordingly to specify the button images.)
- *
- * TPager raises an {@link onPageIndexChanged OnPageIndexChanged} event when
- * the end-user interacts with it and specifies a new page (e.g. clicking
- * on a page button that leads to a new page.) The new page index may be obtained
- * from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}.
- * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex}
- * to this new page index so that the new page of data is rendered.
- *
- * Multiple pagers can be associated with the same data-bound control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.2
- */
-class TPager extends TWebControl implements INamingContainer
-{
- /**
- * Command name that TPager understands.
- */
- const CMD_PAGE='Page';
- const CMD_PAGE_NEXT='Next';
- const CMD_PAGE_PREV='Previous';
- const CMD_PAGE_FIRST='First';
- const CMD_PAGE_LAST='Last';
-
- private $_pageCount=0;
-
- /**
- * Restores the pager state.
- * This method overrides the parent implementation and is invoked when
- * the control is loading persistent state.
- */
- public function loadState()
- {
- parent::loadState();
- if($this->getEnableViewState(true))
- {
- $this->getControls()->clear();
- $this->buildPager();
- }
- }
-
- /**
- * @return string the ID path of the control whose content would be paginated.
- */
- public function getControlToPaginate()
- {
- return $this->getViewState('ControlToPaginate','');
- }
-
- /**
- * Sets the ID path of the control whose content would be paginated.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the pager's naming container to the target control.
- * @param string the ID path
- */
- public function setControlToPaginate($value)
- {
- $this->setViewState('ControlToPaginate',$value,'');
- }
-
- /**
- * @return TPagerMode pager mode. Defaults to TPagerMode::NextPrev.
- */
- public function getMode()
- {
- return $this->getViewState('Mode',TPagerMode::NextPrev);
- }
-
- /**
- * @param TPagerMode pager mode.
- */
- public function setMode($value)
- {
- $this->setViewState('Mode',TPropertyValue::ensureEnum($value,'TPagerMode'),TPagerMode::NextPrev);
- }
-
- /**
- * @return TPagerButtonType the type of command button for paging. Defaults to TPagerButtonType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TPagerButtonType::LinkButton);
- }
-
- /**
- * @param TPagerButtonType the type of command button for paging.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TPagerButtonType'),TPagerButtonType::LinkButton);
- }
-
- /**
- * @return string text for the next page button. Defaults to '>'.
- */
- public function getNextPageText()
- {
- return $this->getViewState('NextPageText','>');
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setNextPageText($value)
- {
- $this->setViewState('NextPageText',$value,'>');
- }
-
- /**
- * @return string text for the previous page button. Defaults to '<'.
- */
- public function getPrevPageText()
- {
- return $this->getViewState('PrevPageText','<');
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setPrevPageText($value)
- {
- $this->setViewState('PrevPageText',$value,'<');
- }
-
- /**
- * @return string text for the first page button. Defaults to '<<'.
- */
- public function getFirstPageText()
- {
- return $this->getViewState('FirstPageText','<<');
- }
-
- /**
- * @param string text for the first page button. If empty, the first page button will not be rendered.
- */
- public function setFirstPageText($value)
- {
- $this->setViewState('FirstPageText',$value,'<<');
- }
-
- /**
- * @return string text for the last page button. Defaults to '>>'.
- */
- public function getLastPageText()
- {
- return $this->getViewState('LastPageText','>>');
- }
-
- /**
- * @param string text for the last page button. If empty, the last page button will not be rendered.
- */
- public function setLastPageText($value)
- {
- $this->setViewState('LastPageText',$value,'>>');
- }
-
- /**
- * @return string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getFirstPageImageUrl()
- {
- return $this->getViewState('FirstPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setFirstPageImageUrl($value)
- {
- $this->setViewState('FirstPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getLastPageImageUrl()
- {
- return $this->getViewState('LastPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setLastPageImageUrl($value)
- {
- $this->setViewState('LastPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getNextPageImageUrl()
- {
- return $this->getViewState('NextPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setNextPageImageUrl($value)
- {
- $this->setViewState('NextPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getPrevPageImageUrl()
- {
- return $this->getViewState('PrevPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setPrevPageImageUrl($value)
- {
- $this->setViewState('PrevPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
- * @see setNumericPageImageUrl
- * @since 3.1.1
- */
- public function getNumericPageImageUrl()
- {
- return $this->getViewState('NumericPageImageUrl','');
- }
-
- /**
- * Sets the image URL for the numeric page buttons.
- * This is actually a template for generating a set of URLs corresponding to numeric button 1, 2, 3, .., etc.
- * Use {0} as the placeholder for the numbers.
- * For example, the image URL http://example.com/images/button{0}.gif
- * will be replaced as http://example.com/images/button1.gif, http://example.com/images/button2.gif, etc.
- * @param string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
- * @since 3.1.1
- */
- public function setNumericPageImageUrl($value)
- {
- $this->setViewState('NumericPageImageUrl',$value);
- }
-
- /**
- * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
- */
- public function getPageButtonCount()
- {
- return $this->getViewState('PageButtonCount',10);
- }
-
- /**
- * @param integer maximum number of pager buttons to be displayed
- * @throws TInvalidDataValueException if the value is less than 1.
- */
- public function setPageButtonCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('pager_pagebuttoncount_invalid');
- $this->setViewState('PageButtonCount',$value,10);
- }
-
- /**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- protected function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_currentpageindex_invalid');
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer number of pages of data items available
- */
- public function getPageCount()
- {
- return $this->getViewState('PageCount',0);
- }
-
- /**
- * @param integer number of pages of data items available
- * @throws TInvalidDataValueException if the value is less than 0
- */
- protected function setPageCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_pagecount_invalid');
- $this->setViewState('PageCount',$value,0);
- }
-
- /**
- * @return boolean whether the current page is the first page Defaults to false.
- */
- public function getIsFirstPage()
- {
- return $this->getCurrentPageIndex()===0;
- }
-
- /**
- * @return boolean whether the current page is the last page
- */
- public function getIsLastPage()
- {
- return $this->getCurrentPageIndex()===$this->getPageCount()-1;
- }
-
- /**
- * Performs databinding to populate data items from data source.
- * This method is invoked by {@link dataBind()}.
- * You may override this function to provide your own way of data population.
- * @param Traversable the bound data
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- $controlID=$this->getControlToPaginate();
- if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl))
- throw new TConfigurationException('pager_controltopaginate_invalid',$controlID);
-
- if($targetControl->getAllowPaging())
- {
- $this->_pageCount=$targetControl->getPageCount();
- $this->getControls()->clear();
- $this->setPageCount($targetControl->getPageCount());
- $this->setCurrentPageIndex($targetControl->getCurrentPageIndex());
- $this->buildPager();
- }
- else
- $this->_pageCount=0;
- }
-
- /**
- * Renders the control.
- * The method overrides the parent implementation by rendering
- * the pager only when there are two or more pages.
- * @param THtmlWriter the writer
- */
- public function render($writer)
- {
- if($this->_pageCount>1)
- parent::render($writer);
- }
-
- /**
- * Builds the pager content based on the pager mode.
- * Current implementation includes building 'NextPrev', 'Numeric' and 'DropDownList' pagers.
- * Derived classes may override this method to provide additional pagers.
- */
- protected function buildPager()
- {
- switch($this->getMode())
- {
- case TPagerMode::NextPrev:
- $this->buildNextPrevPager();
- break;
- case TPagerMode::Numeric:
- $this->buildNumericPager();
- break;
- case TPagerMode::DropDownList:
- $this->buildListPager();
- break;
- }
- }
-
- /**
- * Creates a pager button.
- * Depending on the button type, a TLinkButton or a TButton may be created.
- * If it is enabled (clickable), its command name and parameter will also be set.
- * Derived classes may override this method to create additional types of buttons, such as TImageButton.
- * @param string button type, either LinkButton or PushButton
- * @param boolean whether the button should be enabled
- * @param string caption of the button.
- * @param string CommandName corresponding to the OnCommand event of the button.
- * @param string CommandParameter corresponding to the OnCommand event of the button
- * @return mixed the button instance
- */
- protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
- {
- if($buttonType===TPagerButtonType::LinkButton)
- {
- if($enabled)
- $button=new TLinkButton;
- else
- {
- $button=new TLabel;
- $button->setText($text);
- return $button;
- }
- }
- else
- {
- if($buttonType===TPagerButtonType::ImageButton)
- {
- $button=new TImageButton;
- $button->setImageUrl($this->getPageImageUrl($text,$commandName));
- }
- else
- $button=new TButton;
- if(!$enabled)
- $button->setEnabled(false);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCommandParameter($commandParameter);
- $button->setCausesValidation(false);
- return $button;
- }
-
- /**
- * @param string the caption of the image button
- * @param string the command name associated with the image button
- * @since 3.1.1
- */
- protected function getPageImageUrl($text,$commandName)
- {
- switch($commandName)
- {
- case self::CMD_PAGE:
- $url=$this->getNumericPageImageUrl();
- return str_replace('{0}',$text,$url);
- case self::CMD_PAGE_NEXT:
- return $this->getNextPageImageUrl();
- case self::CMD_PAGE_PREV:
- return $this->getPrevPageImageUrl();
- case self::CMD_PAGE_FIRST:
- return $this->getFirstPageImageUrl();
- case self::CMD_PAGE_LAST:
- return $this->getLastPageImageUrl();
- default:
- return '';
- }
- }
-
- /**
- * Builds a next-prev pager
- */
- protected function buildNextPrevPager()
- {
- $buttonType=$this->getButtonType();
- $controls=$this->getControls();
- if($this->getIsFirstPage())
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($label);
- $controls->add("\n");
- }
- $label=$this->createPagerButton($buttonType,false,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
- $controls->add($label);
- }
- else
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($button);
- $controls->add("\n");
- }
- $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
- $controls->add($button);
- }
- $controls->add("\n");
- if($this->getIsLastPage())
- {
- $label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
- $controls->add($label);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_LAST,'');
- $controls->add($label);
- }
- }
- else
- {
- $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
- $controls->add($button);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a numeric pager
- */
- protected function buildNumericPager()
- {
- $buttonType=$this->getButtonType();
- $controls=$this->getControls();
- $pageCount=$this->getPageCount();
- $pageIndex=$this->getCurrentPageIndex()+1;
- $maxButtonCount=$this->getPageButtonCount();
- $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
- $startPageIndex=1;
- $endPageIndex=$buttonCount;
- if($pageIndex>$endPageIndex)
- {
- $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
- if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
- $endPageIndex=$pageCount;
- if($endPageIndex-$startPageIndex+1<$maxButtonCount)
- {
- if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
- $startPageIndex=1;
- }
- }
-
- if($startPageIndex>1)
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($button);
- $controls->add("\n");
- }
- $prevPageIndex=$startPageIndex-1;
- $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
- $controls->add($button);
- $controls->add("\n");
- }
-
- for($i=$startPageIndex;$i<=$endPageIndex;++$i)
- {
- if($i===$pageIndex)
- {
- $label=$this->createPagerButton($buttonType,false,"$i",self::CMD_PAGE,'');
- $controls->add($label);
- }
- else
- {
- $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
- $controls->add($button);
- }
- if($i<$endPageIndex)
- $controls->add("\n");
- }
-
- if($pageCount>$endPageIndex)
- {
- $controls->add("\n");
- $nextPageIndex=$endPageIndex+1;
- $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
- $controls->add($button);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a dropdown list pager
- */
- protected function buildListPager()
- {
- $list=new TDropDownList;
- $this->getControls()->add($list);
- $list->setDataSource(range(1,$this->getPageCount()));
- $list->dataBind();
- $list->setSelectedIndex($this->getCurrentPageIndex());
- $list->setAutoPostBack(true);
- $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
- }
-
- /**
- * Event handler to the OnSelectedIndexChanged event of the dropdown list.
- * This handler will raise {@link onPageIndexChanged OnPageIndexChanged} event.
- * @param TDropDownList the dropdown list control raising the event
- * @param TEventParameter event parameter
- */
- public function listIndexChanged($sender,$param)
- {
- $pageIndex=$sender->getSelectedIndex();
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- }
-
- /**
- * This event is raised when page index is changed due to a page button click.
- * @param TPagerPageChangedEventParameter event parameter
- */
- public function onPageIndexChanged($param)
- {
- $this->raiseEvent('OnPageIndexChanged',$this,$param);
- }
-
- /**
- * Processes a bubbled event.
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_PAGE)===0)
- {
- $pageIndex=TPropertyValue::ensureInteger($param->getCommandParameter())-1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_NEXT)===0)
- {
- $pageIndex=$this->getCurrentPageIndex()+1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_PREV)===0)
- {
- $pageIndex=$this->getCurrentPageIndex()-1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_FIRST)===0)
- {
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,0));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_LAST)===0)
- {
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$this->getPageCount()-1));
- return true;
- }
- return false;
- }
- else
- return false;
- }
-}
-
-/**
- * TPagerPageChangedEventParameter class
- *
- * TPagerPageChangedEventParameter encapsulates the parameter data for
- * {@link TPager::onPageIndexChanged PageIndexChanged} event of {@link TPager} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
- * returns the new page index carried with the page command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.2
- */
-class TPagerPageChangedEventParameter extends TEventParameter
-{
- /**
- * @var integer new page index
- */
- private $_newIndex;
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param integer new page index
- */
- public function __construct($source,$newPageIndex)
- {
- $this->_source=$source;
- $this->_newIndex=$newPageIndex;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return integer new page index
- */
- public function getNewPageIndex()
- {
- return $this->_newIndex;
- }
-}
-
-
-/**
- * TPagerMode class.
- * TPagerMode defines the enumerable type for the possible modes that a {@link TPager} control can take.
- *
- * The following enumerable values are defined:
- * - NextPrev: pager buttons are displayed as next and previous pages
- * - Numeric: pager buttons are displayed as numeric page numbers
- * - DropDownList: a dropdown list is used to select pages
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TPagerMode extends TEnumerable
-{
- const NextPrev='NextPrev';
- const Numeric='Numeric';
- const DropDownList='DropDownList';
-}
-
-
-/**
- * TPagerButtonType class.
- * TPagerButtonType defines the enumerable type for the possible types of pager buttons.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form submit buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TPagerButtonType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
- const ImageButton='ImageButton';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TPager class. + * + * TPager creates a pager that provides UI for end-users to interactively + * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control, + * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc. + * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate}, + * which must be the ID path of the target control reaching from the pager's + * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging} + * set to true. + * + * TPager can display three different UIs, specified via {@link setMode Mode}: + * - NextPrev: a next page and a previous page button are rendered. + * - Numeric: a list of page index buttons are rendered. + * - List: a dropdown list of page indices are rendered. + * + * When the pager mode is either NextPrev or Numeric, the paging buttons may be displayed + * in three types by setting {@link setButtonType ButtonType}: + * - LinkButton: a hyperlink button + * - PushButton: a normal button + * - ImageButton: an image button (please set XXXPageImageUrl properties accordingly to specify the button images.) + * + * TPager raises an {@link onPageIndexChanged OnPageIndexChanged} event when + * the end-user interacts with it and specifies a new page (e.g. clicking + * on a page button that leads to a new page.) The new page index may be obtained + * from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}. + * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex} + * to this new page index so that the new page of data is rendered. + * + * Multiple pagers can be associated with the same data-bound control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.2 + */ +class TPager extends TWebControl implements INamingContainer +{ + /** + * Command name that TPager understands. + */ + const CMD_PAGE='Page'; + const CMD_PAGE_NEXT='Next'; + const CMD_PAGE_PREV='Previous'; + const CMD_PAGE_FIRST='First'; + const CMD_PAGE_LAST='Last'; + + private $_pageCount=0; + + /** + * Restores the pager state. + * This method overrides the parent implementation and is invoked when + * the control is loading persistent state. + */ + public function loadState() + { + parent::loadState(); + if($this->getEnableViewState(true)) + { + $this->getControls()->clear(); + $this->buildPager(); + } + } + + /** + * @return string the ID path of the control whose content would be paginated. + */ + public function getControlToPaginate() + { + return $this->getViewState('ControlToPaginate',''); + } + + /** + * Sets the ID path of the control whose content would be paginated. + * The ID path is the dot-connected IDs of the controls reaching from + * the pager's naming container to the target control. + * @param string the ID path + */ + public function setControlToPaginate($value) + { + $this->setViewState('ControlToPaginate',$value,''); + } + + /** + * @return TPagerMode pager mode. Defaults to TPagerMode::NextPrev. + */ + public function getMode() + { + return $this->getViewState('Mode',TPagerMode::NextPrev); + } + + /** + * @param TPagerMode pager mode. + */ + public function setMode($value) + { + $this->setViewState('Mode',TPropertyValue::ensureEnum($value,'TPagerMode'),TPagerMode::NextPrev); + } + + /** + * @return TPagerButtonType the type of command button for paging. Defaults to TPagerButtonType::LinkButton. + */ + public function getButtonType() + { + return $this->getViewState('ButtonType',TPagerButtonType::LinkButton); + } + + /** + * @param TPagerButtonType the type of command button for paging. + */ + public function setButtonType($value) + { + $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TPagerButtonType'),TPagerButtonType::LinkButton); + } + + /** + * @return string text for the next page button. Defaults to '>'. + */ + public function getNextPageText() + { + return $this->getViewState('NextPageText','>'); + } + + /** + * @param string text for the next page button. + */ + public function setNextPageText($value) + { + $this->setViewState('NextPageText',$value,'>'); + } + + /** + * @return string text for the previous page button. Defaults to '<'. + */ + public function getPrevPageText() + { + return $this->getViewState('PrevPageText','<'); + } + + /** + * @param string text for the next page button. + */ + public function setPrevPageText($value) + { + $this->setViewState('PrevPageText',$value,'<'); + } + + /** + * @return string text for the first page button. Defaults to '<<'. + */ + public function getFirstPageText() + { + return $this->getViewState('FirstPageText','<<'); + } + + /** + * @param string text for the first page button. If empty, the first page button will not be rendered. + */ + public function setFirstPageText($value) + { + $this->setViewState('FirstPageText',$value,'<<'); + } + + /** + * @return string text for the last page button. Defaults to '>>'. + */ + public function getLastPageText() + { + return $this->getViewState('LastPageText','>>'); + } + + /** + * @param string text for the last page button. If empty, the last page button will not be rendered. + */ + public function setLastPageText($value) + { + $this->setViewState('LastPageText',$value,'>>'); + } + + /** + * @return string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function getFirstPageImageUrl() + { + return $this->getViewState('FirstPageImageUrl',''); + } + + /** + * @param string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function setFirstPageImageUrl($value) + { + $this->setViewState('FirstPageImageUrl',$value); + } + + /** + * @return string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function getLastPageImageUrl() + { + return $this->getViewState('LastPageImageUrl',''); + } + + /** + * @param string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function setLastPageImageUrl($value) + { + $this->setViewState('LastPageImageUrl',$value); + } + + /** + * @return string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function getNextPageImageUrl() + { + return $this->getViewState('NextPageImageUrl',''); + } + + /** + * @param string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function setNextPageImageUrl($value) + { + $this->setViewState('NextPageImageUrl',$value); + } + + /** + * @return string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function getPrevPageImageUrl() + { + return $this->getViewState('PrevPageImageUrl',''); + } + + /** + * @param string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'. + * @since 3.1.1 + */ + public function setPrevPageImageUrl($value) + { + $this->setViewState('PrevPageImageUrl',$value); + } + + /** + * @return string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'. + * @see setNumericPageImageUrl + * @since 3.1.1 + */ + public function getNumericPageImageUrl() + { + return $this->getViewState('NumericPageImageUrl',''); + } + + /** + * Sets the image URL for the numeric page buttons. + * This is actually a template for generating a set of URLs corresponding to numeric button 1, 2, 3, .., etc. + * Use {0} as the placeholder for the numbers. + * For example, the image URL http://example.com/images/button{0}.gif + * will be replaced as http://example.com/images/button1.gif, http://example.com/images/button2.gif, etc. + * @param string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'. + * @since 3.1.1 + */ + public function setNumericPageImageUrl($value) + { + $this->setViewState('NumericPageImageUrl',$value); + } + + /** + * @return integer maximum number of pager buttons to be displayed. Defaults to 10. + */ + public function getPageButtonCount() + { + return $this->getViewState('PageButtonCount',10); + } + + /** + * @param integer maximum number of pager buttons to be displayed + * @throws TInvalidDataValueException if the value is less than 1. + */ + public function setPageButtonCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<1) + throw new TInvalidDataValueException('pager_pagebuttoncount_invalid'); + $this->setViewState('PageButtonCount',$value,10); + } + + /** + * @return integer the zero-based index of the current page. Defaults to 0. + */ + public function getCurrentPageIndex() + { + return $this->getViewState('CurrentPageIndex',0); + } + + /** + * @param integer the zero-based index of the current page + * @throws TInvalidDataValueException if the value is less than 0 + */ + protected function setCurrentPageIndex($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('pager_currentpageindex_invalid'); + $this->setViewState('CurrentPageIndex',$value,0); + } + + /** + * @return integer number of pages of data items available + */ + public function getPageCount() + { + return $this->getViewState('PageCount',0); + } + + /** + * @param integer number of pages of data items available + * @throws TInvalidDataValueException if the value is less than 0 + */ + protected function setPageCount($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('pager_pagecount_invalid'); + $this->setViewState('PageCount',$value,0); + } + + /** + * @return boolean whether the current page is the first page Defaults to false. + */ + public function getIsFirstPage() + { + return $this->getCurrentPageIndex()===0; + } + + /** + * @return boolean whether the current page is the last page + */ + public function getIsLastPage() + { + return $this->getCurrentPageIndex()===$this->getPageCount()-1; + } + + /** + * Performs databinding to populate data items from data source. + * This method is invoked by {@link dataBind()}. + * You may override this function to provide your own way of data population. + * @param Traversable the bound data + */ + public function onPreRender($param) + { + parent::onPreRender($param); + + $controlID=$this->getControlToPaginate(); + if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl)) + throw new TConfigurationException('pager_controltopaginate_invalid',$controlID); + + if($targetControl->getAllowPaging()) + { + $this->_pageCount=$targetControl->getPageCount(); + $this->getControls()->clear(); + $this->setPageCount($targetControl->getPageCount()); + $this->setCurrentPageIndex($targetControl->getCurrentPageIndex()); + $this->buildPager(); + } + else + $this->_pageCount=0; + } + + /** + * Renders the control. + * The method overrides the parent implementation by rendering + * the pager only when there are two or more pages. + * @param THtmlWriter the writer + */ + public function render($writer) + { + if($this->_pageCount>1) + parent::render($writer); + } + + /** + * Builds the pager content based on the pager mode. + * Current implementation includes building 'NextPrev', 'Numeric' and 'DropDownList' pagers. + * Derived classes may override this method to provide additional pagers. + */ + protected function buildPager() + { + switch($this->getMode()) + { + case TPagerMode::NextPrev: + $this->buildNextPrevPager(); + break; + case TPagerMode::Numeric: + $this->buildNumericPager(); + break; + case TPagerMode::DropDownList: + $this->buildListPager(); + break; + } + } + + /** + * Creates a pager button. + * Depending on the button type, a TLinkButton or a TButton may be created. + * If it is enabled (clickable), its command name and parameter will also be set. + * Derived classes may override this method to create additional types of buttons, such as TImageButton. + * @param string button type, either LinkButton or PushButton + * @param boolean whether the button should be enabled + * @param string caption of the button. + * @param string CommandName corresponding to the OnCommand event of the button. + * @param string CommandParameter corresponding to the OnCommand event of the button + * @return mixed the button instance + */ + protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter) + { + if($buttonType===TPagerButtonType::LinkButton) + { + if($enabled) + $button=new TLinkButton; + else + { + $button=new TLabel; + $button->setText($text); + return $button; + } + } + else + { + if($buttonType===TPagerButtonType::ImageButton) + { + $button=new TImageButton; + $button->setImageUrl($this->getPageImageUrl($text,$commandName)); + } + else + $button=new TButton; + if(!$enabled) + $button->setEnabled(false); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCommandParameter($commandParameter); + $button->setCausesValidation(false); + return $button; + } + + /** + * @param string the caption of the image button + * @param string the command name associated with the image button + * @since 3.1.1 + */ + protected function getPageImageUrl($text,$commandName) + { + switch($commandName) + { + case self::CMD_PAGE: + $url=$this->getNumericPageImageUrl(); + return str_replace('{0}',$text,$url); + case self::CMD_PAGE_NEXT: + return $this->getNextPageImageUrl(); + case self::CMD_PAGE_PREV: + return $this->getPrevPageImageUrl(); + case self::CMD_PAGE_FIRST: + return $this->getFirstPageImageUrl(); + case self::CMD_PAGE_LAST: + return $this->getLastPageImageUrl(); + default: + return ''; + } + } + + /** + * Builds a next-prev pager + */ + protected function buildNextPrevPager() + { + $buttonType=$this->getButtonType(); + $controls=$this->getControls(); + if($this->getIsFirstPage()) + { + if(($text=$this->getFirstPageText())!=='') + { + $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_FIRST,''); + $controls->add($label); + $controls->add("\n"); + } + $label=$this->createPagerButton($buttonType,false,$this->getPrevPageText(),self::CMD_PAGE_PREV,''); + $controls->add($label); + } + else + { + if(($text=$this->getFirstPageText())!=='') + { + $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,''); + $controls->add($button); + $controls->add("\n"); + } + $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE_PREV,''); + $controls->add($button); + } + $controls->add("\n"); + if($this->getIsLastPage()) + { + $label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),self::CMD_PAGE_NEXT,''); + $controls->add($label); + if(($text=$this->getLastPageText())!=='') + { + $controls->add("\n"); + $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_LAST,''); + $controls->add($label); + } + } + else + { + $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE_NEXT,''); + $controls->add($button); + if(($text=$this->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,''); + $controls->add($button); + } + } + } + + /** + * Builds a numeric pager + */ + protected function buildNumericPager() + { + $buttonType=$this->getButtonType(); + $controls=$this->getControls(); + $pageCount=$this->getPageCount(); + $pageIndex=$this->getCurrentPageIndex()+1; + $maxButtonCount=$this->getPageButtonCount(); + $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount; + $startPageIndex=1; + $endPageIndex=$buttonCount; + if($pageIndex>$endPageIndex) + { + $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1; + if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount) + $endPageIndex=$pageCount; + if($endPageIndex-$startPageIndex+1<$maxButtonCount) + { + if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1) + $startPageIndex=1; + } + } + + if($startPageIndex>1) + { + if(($text=$this->getFirstPageText())!=='') + { + $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,''); + $controls->add($button); + $controls->add("\n"); + } + $prevPageIndex=$startPageIndex-1; + $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex"); + $controls->add($button); + $controls->add("\n"); + } + + for($i=$startPageIndex;$i<=$endPageIndex;++$i) + { + if($i===$pageIndex) + { + $label=$this->createPagerButton($buttonType,false,"$i",self::CMD_PAGE,''); + $controls->add($label); + } + else + { + $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i"); + $controls->add($button); + } + if($i<$endPageIndex) + $controls->add("\n"); + } + + if($pageCount>$endPageIndex) + { + $controls->add("\n"); + $nextPageIndex=$endPageIndex+1; + $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE,"$nextPageIndex"); + $controls->add($button); + if(($text=$this->getLastPageText())!=='') + { + $controls->add("\n"); + $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,''); + $controls->add($button); + } + } + } + + /** + * Builds a dropdown list pager + */ + protected function buildListPager() + { + $list=new TDropDownList; + $this->getControls()->add($list); + $list->setDataSource(range(1,$this->getPageCount())); + $list->dataBind(); + $list->setSelectedIndex($this->getCurrentPageIndex()); + $list->setAutoPostBack(true); + $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged')); + } + + /** + * Event handler to the OnSelectedIndexChanged event of the dropdown list. + * This handler will raise {@link onPageIndexChanged OnPageIndexChanged} event. + * @param TDropDownList the dropdown list control raising the event + * @param TEventParameter event parameter + */ + public function listIndexChanged($sender,$param) + { + $pageIndex=$sender->getSelectedIndex(); + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex)); + } + + /** + * This event is raised when page index is changed due to a page button click. + * @param TPagerPageChangedEventParameter event parameter + */ + public function onPageIndexChanged($param) + { + $this->raiseEvent('OnPageIndexChanged',$this,$param); + } + + /** + * Processes a bubbled event. + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_PAGE)===0) + { + $pageIndex=TPropertyValue::ensureInteger($param->getCommandParameter())-1; + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE_NEXT)===0) + { + $pageIndex=$this->getCurrentPageIndex()+1; + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE_PREV)===0) + { + $pageIndex=$this->getCurrentPageIndex()-1; + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE_FIRST)===0) + { + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,0)); + return true; + } + else if(strcasecmp($command,self::CMD_PAGE_LAST)===0) + { + $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$this->getPageCount()-1)); + return true; + } + return false; + } + else + return false; + } +} + +/** + * TPagerPageChangedEventParameter class + * + * TPagerPageChangedEventParameter encapsulates the parameter data for + * {@link TPager::onPageIndexChanged PageIndexChanged} event of {@link TPager} controls. + * + * The {@link getCommandSource CommandSource} property refers to the control + * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex} + * returns the new page index carried with the page command. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.2 + */ +class TPagerPageChangedEventParameter extends TEventParameter +{ + /** + * @var integer new page index + */ + private $_newIndex; + /** + * @var TControl original event sender + */ + private $_source=null; + + /** + * Constructor. + * @param TControl the control originally raises the <b>OnCommand</b> event. + * @param integer new page index + */ + public function __construct($source,$newPageIndex) + { + $this->_source=$source; + $this->_newIndex=$newPageIndex; + } + + /** + * @return TControl the control originally raises the <b>OnCommand</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } + + /** + * @return integer new page index + */ + public function getNewPageIndex() + { + return $this->_newIndex; + } +} + + +/** + * TPagerMode class. + * TPagerMode defines the enumerable type for the possible modes that a {@link TPager} control can take. + * + * The following enumerable values are defined: + * - NextPrev: pager buttons are displayed as next and previous pages + * - Numeric: pager buttons are displayed as numeric page numbers + * - DropDownList: a dropdown list is used to select pages + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TPagerMode extends TEnumerable +{ + const NextPrev='NextPrev'; + const Numeric='Numeric'; + const DropDownList='DropDownList'; +} + + +/** + * TPagerButtonType class. + * TPagerButtonType defines the enumerable type for the possible types of pager buttons. + * + * The following enumerable values are defined: + * - LinkButton: link buttons + * - PushButton: form submit buttons + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TPagerButtonType extends TEnumerable +{ + const LinkButton='LinkButton'; + const PushButton='PushButton'; + const ImageButton='ImageButton'; +} + diff --git a/framework/Web/UI/WebControls/TPanel.php b/framework/Web/UI/WebControls/TPanel.php index 5d651679..d4e05136 100644 --- a/framework/Web/UI/WebControls/TPanel.php +++ b/framework/Web/UI/WebControls/TPanel.php @@ -1,246 +1,246 @@ -<?php
-/**
- * TPanel class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TPanelStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TPanelStyle');
-
-/**
- * TPanel class
- *
- * TPanel represents a component that acts as a container for other component.
- * It is especially useful when you want to generate components programmatically
- * or hide/show a group of components.
- *
- * By default, TPanel displays a <div> element on a page.
- * Children of TPanel are displayed as the body content of the element.
- * The property {@link setWrap Wrap} can be used to set whether the body content
- * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
- * the content is aligned horizontally, and {@link getDirection Direction} indicates
- * the content direction (left to right or right to left). You can set
- * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
- * and you can ste {@link setGroupingText GroupingText} so that the panel is
- * displayed as a field set with a legend text. Finally, you can specify
- * a default button to be fired when users press 'return' key within the panel
- * by setting the {@link setDefaultButton DefaultButton} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPanel extends TWebControl
-{
- /**
- * @var string ID path to the default button
- */
- private $_defaultButton='';
-
- /**
- * @return string tag name of the panel
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Creates a style object to be used by the control.
- * This method overrides the parent impementation by creating a TPanelStyle object.
- * @return TPanelStyle the style used by TPanel.
- */
- protected function createStyle()
- {
- return new TPanelStyle;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- * @throws TInvalidDataValueException if default button is not right.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($butt=$this->getDefaultButton())!=='')
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * @return boolean whether the content wraps within the panel. Defaults to true.
- */
- public function getWrap()
- {
- return $this->getStyle()->getWrap();
- }
-
- /**
- * Sets the value indicating whether the content wraps within the panel.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->getStyle()->setWrap($value);
- }
-
- /**
- * @return string the horizontal alignment of the contents within the panel, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- return $this->getStyle()->getHorizontalAlign();
- }
-
- /**
- * Sets the horizontal alignment of the contents within the panel.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the URL of the background image for the panel component.
- */
- public function getBackImageUrl()
- {
- return $this->getStyle()->getBackImageUrl();
- }
-
- /**
- * Sets the URL of the background image for the panel component.
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * @return string alignment of the content in the panel. Defaults to 'NotSet'.
- */
- public function getDirection()
- {
- return $this->getStyle()->getDirection();
- }
-
- /**
- * @param string alignment of the content in the panel.
- * Valid values include 'NotSet', 'LeftToRight', 'RightToLeft'.
- */
- public function setDirection($value)
- {
- $this->getStyle()->setDirection($value);
- }
-
- /**
- * @return string the ID path to the default button. Defaults to empty.
- */
- public function getDefaultButton()
- {
- return $this->_defaultButton;
- }
-
- /**
- * Specifies the default button for the panel.
- * The default button will be fired (clicked) whenever a user enters 'return'
- * key within the panel.
- * The button must be locatable via the function call {@link TControl::findControl findControl}.
- * @param string the ID path to the default button.
- */
- public function setDefaultButton($value)
- {
- $this->_defaultButton=$value;
- }
-
- /**
- * @return string the legend text when the panel is used as a fieldset. Defaults to empty.
- */
- public function getGroupingText()
- {
- return $this->getViewState('GroupingText','');
- }
-
- /**
- * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset.
- */
- public function setGroupingText($value)
- {
- $this->setViewState('GroupingText',$value,'');
- }
-
- /**
- * @return string the visibility and position of scroll bars in a panel control, defaults to None.
- */
- public function getScrollBars()
- {
- return $this->getStyle()->getScrollBars();
- }
-
- /**
- * @param string the visibility and position of scroll bars in a panel control.
- * Valid values include None, Auto, Both, Horizontal and Vertical.
- */
- public function setScrollBars($value)
- {
- $this->getStyle()->setScrollBars($value);
- }
-
- /**
- * Renders the openning tag for the control (including attributes)
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($text=$this->getGroupingText())!=='')
- {
- $writer->renderBeginTag('fieldset');
- $writer->renderBeginTag('legend');
- $writer->write($text);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the closing tag for the control
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- if($this->getGroupingText()!=='')
- $writer->renderEndTag();
- parent::renderEndTag($writer);
- }
-
- public function render($writer)
- {
- parent::render($writer);
-
- if(($butt=$this->getDefaultButton())!=='')
- {
- $buttons = $this->findControlsByID($butt);
- if (count($buttons)>0)
- $button = reset($buttons);
- else
- $button = null;
- if($button===null)
- throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt);
- else
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
- }
-}
-
+<?php +/** + * TPanel class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TPanelStyle class file + */ +Prado::using('System.Web.UI.WebControls.TPanelStyle'); + +/** + * TPanel class + * + * TPanel represents a component that acts as a container for other component. + * It is especially useful when you want to generate components programmatically + * or hide/show a group of components. + * + * By default, TPanel displays a <div> element on a page. + * Children of TPanel are displayed as the body content of the element. + * The property {@link setWrap Wrap} can be used to set whether the body content + * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how + * the content is aligned horizontally, and {@link getDirection Direction} indicates + * the content direction (left to right or right to left). You can set + * {@link setBackImageUrl BackImageUrl} to give a background image to the panel, + * and you can ste {@link setGroupingText GroupingText} so that the panel is + * displayed as a field set with a legend text. Finally, you can specify + * a default button to be fired when users press 'return' key within the panel + * by setting the {@link setDefaultButton DefaultButton} property. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TPanel extends TWebControl +{ + /** + * @var string ID path to the default button + */ + private $_defaultButton=''; + + /** + * @return string tag name of the panel + */ + protected function getTagName() + { + return 'div'; + } + + /** + * Creates a style object to be used by the control. + * This method overrides the parent impementation by creating a TPanelStyle object. + * @return TPanelStyle the style used by TPanel. + */ + protected function createStyle() + { + return new TPanelStyle; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + * @throws TInvalidDataValueException if default button is not right. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if(($butt=$this->getDefaultButton())!=='') + $writer->addAttribute('id',$this->getClientID()); + } + + /** + * @return boolean whether the content wraps within the panel. Defaults to true. + */ + public function getWrap() + { + return $this->getStyle()->getWrap(); + } + + /** + * Sets the value indicating whether the content wraps within the panel. + * @param boolean whether the content wraps within the panel. + */ + public function setWrap($value) + { + $this->getStyle()->setWrap($value); + } + + /** + * @return string the horizontal alignment of the contents within the panel, defaults to 'NotSet'. + */ + public function getHorizontalAlign() + { + return $this->getStyle()->getHorizontalAlign(); + } + + /** + * Sets the horizontal alignment of the contents within the panel. + * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center' + * @param string the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return string the URL of the background image for the panel component. + */ + public function getBackImageUrl() + { + return $this->getStyle()->getBackImageUrl(); + } + + /** + * Sets the URL of the background image for the panel component. + * @param string the URL + */ + public function setBackImageUrl($value) + { + $this->getStyle()->setBackImageUrl($value); + } + + /** + * @return string alignment of the content in the panel. Defaults to 'NotSet'. + */ + public function getDirection() + { + return $this->getStyle()->getDirection(); + } + + /** + * @param string alignment of the content in the panel. + * Valid values include 'NotSet', 'LeftToRight', 'RightToLeft'. + */ + public function setDirection($value) + { + $this->getStyle()->setDirection($value); + } + + /** + * @return string the ID path to the default button. Defaults to empty. + */ + public function getDefaultButton() + { + return $this->_defaultButton; + } + + /** + * Specifies the default button for the panel. + * The default button will be fired (clicked) whenever a user enters 'return' + * key within the panel. + * The button must be locatable via the function call {@link TControl::findControl findControl}. + * @param string the ID path to the default button. + */ + public function setDefaultButton($value) + { + $this->_defaultButton=$value; + } + + /** + * @return string the legend text when the panel is used as a fieldset. Defaults to empty. + */ + public function getGroupingText() + { + return $this->getViewState('GroupingText',''); + } + + /** + * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset. + */ + public function setGroupingText($value) + { + $this->setViewState('GroupingText',$value,''); + } + + /** + * @return string the visibility and position of scroll bars in a panel control, defaults to None. + */ + public function getScrollBars() + { + return $this->getStyle()->getScrollBars(); + } + + /** + * @param string the visibility and position of scroll bars in a panel control. + * Valid values include None, Auto, Both, Horizontal and Vertical. + */ + public function setScrollBars($value) + { + $this->getStyle()->setScrollBars($value); + } + + /** + * Renders the openning tag for the control (including attributes) + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + parent::renderBeginTag($writer); + if(($text=$this->getGroupingText())!=='') + { + $writer->renderBeginTag('fieldset'); + $writer->renderBeginTag('legend'); + $writer->write($text); + $writer->renderEndTag(); + } + } + + /** + * Renders the closing tag for the control + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderEndTag($writer) + { + if($this->getGroupingText()!=='') + $writer->renderEndTag(); + parent::renderEndTag($writer); + } + + public function render($writer) + { + parent::render($writer); + + if(($butt=$this->getDefaultButton())!=='') + { + $buttons = $this->findControlsByID($butt); + if (count($buttons)>0) + $button = reset($buttons); + else + $button = null; + if($button===null) + throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt); + else + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + } + } +} + diff --git a/framework/Web/UI/WebControls/TPanelStyle.php b/framework/Web/UI/WebControls/TPanelStyle.php index 16169749..5e5db6e4 100644 --- a/framework/Web/UI/WebControls/TPanelStyle.php +++ b/framework/Web/UI/WebControls/TPanelStyle.php @@ -1,278 +1,278 @@ -<?php
-/**
- * TPanelStyle class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TPanelStyle class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TStyle');
-
-/**
- * TPanelStyle class.
- * TPanelStyle represents the CSS style specific for panel HTML tag.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPanelStyle extends TStyle
-{
- /**
- * @var string the URL of the background image for the panel component
- */
- private $_backImageUrl=null;
- /**
- * @var string alignment of the content in the panel.
- */
- private $_direction=null;
- /**
- * @var string horizontal alignment of the contents within the panel
- */
- private $_horizontalAlign=null;
- /**
- * @var string visibility and position of scroll bars
- */
- private $_scrollBars=null;
- /**
- * @var boolean whether the content wraps within the panel
- */
- private $_wrap=null;
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(($url=trim($this->getBackImageUrl()))!=='')
- $this->setStyleField('background-image','url('.$url.')');
-
- switch($this->getScrollBars())
- {
- case TScrollBars::Horizontal: $this->setStyleField('overflow-x','scroll'); break;
- case TScrollBars::Vertical: $this->setStyleField('overflow-y','scroll'); break;
- case TScrollBars::Both: $this->setStyleField('overflow','scroll'); break;
- case TScrollBars::Auto: $this->setStyleField('overflow','auto'); break;
- }
-
- if(($align=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $this->setStyleField('text-align',strtolower($align));
-
- if(!$this->getWrap())
- $this->setStyleField('white-space','nowrap');
-
- if(($direction=$this->getDirection())!==TContentDirection::NotSet)
- {
- if($direction===TContentDirection::LeftToRight)
- $this->setStyleField('direction','ltr');
- else
- $this->setStyleField('direction','rtl');
- }
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string the URL of the background image for the panel component.
- */
- public function getBackImageUrl()
- {
- return $this->_backImageUrl===null?'':$this->_backImageUrl;
- }
-
- /**
- * Sets the URL of the background image for the panel component.
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->_backImageUrl=$value;
- }
-
- /**
- * @return TContentDirection alignment of the content in the panel. Defaults to TContentDirection::NotSet.
- */
- public function getDirection()
- {
- return $this->_direction===null?TContentDirection::NotSet:$this->_direction;
- }
-
- /**
- * @param TContentDirection alignment of the content in the panel.
- */
- public function setDirection($value)
- {
- $this->_direction=TPropertyValue::ensureEnum($value,'TContentDirection');
- }
-
- /**
- * @return boolean whether the content wraps within the panel. Defaults to true.
- */
- public function getWrap()
- {
- return $this->_wrap===null?true:$this->_wrap;
- }
-
- /**
- * Sets the value indicating whether the content wraps within the panel.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->_wrap=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the panel, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the panel.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return TScrollBars the visibility and position of scroll bars in a panel control, defaults to TScrollBars::None.
- */
- public function getScrollBars()
- {
- return $this->_scrollBars===null?TScrollBars::None:$this->_scrollBars;
- }
-
- /**
- * @param TScrollBars the visibility and position of scroll bars in a panel control.
- */
- public function setScrollBars($value)
- {
- $this->_scrollBars=TPropertyValue::ensureEnum($value,'TScrollBars');
- }
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TPanelStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_backImageUrl=null;
- $this->_direction=null;
- $this->_horizontalAlign=null;
- $this->_scrollBars=null;
- $this->_wrap=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TPanelStyle)
- {
- if($style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($style->_direction!==null)
- $this->_direction=$style->_direction;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_scrollBars!==null)
- $this->_scrollBars=$style->_scrollBars;
- if($style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TPanelStyle)
- {
- if($this->_backImageUrl===null && $style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($this->_direction===null && $style->_direction!==null)
- $this->_direction=$style->_direction;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_scrollBars===null && $style->_scrollBars!==null)
- $this->_scrollBars=$style->_scrollBars;
- if($this->_wrap===null && $style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-}
-
-/**
- * TContentDirection class.
- * TContentDirection defines the enumerable type for the possible directions that a panel can be at.
- *
- * The following enumerable values are defined:
- * - NotSet: the direction is not specified
- * - LeftToRight: content in a panel is left to right
- * - RightToLeft: content in a panel is right to left
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TContentDirection extends TEnumerable
-{
- const NotSet='NotSet';
- const LeftToRight='LeftToRight';
- const RightToLeft='RightToLeft';
-}
-
-/**
- * TScrollBars class.
- * TScrollBars defines the enumerable type for the possible scroll bar mode
- * that a {@link TPanel} control could use.
- *
- * The following enumerable values are defined:
- * - None: no scroll bars.
- * - Auto: scroll bars automatically appeared when needed.
- * - Both: show both horizontal and vertical scroll bars all the time.
- * - Horizontal: horizontal scroll bar only
- * - Vertical: vertical scroll bar only
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TScrollBars extends TEnumerable
-{
- const None='None';
- const Auto='Auto';
- const Both='Both';
- const Horizontal='Horizontal';
- const Vertical='Vertical';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TStyle class file + */ +Prado::using('System.Web.UI.WebControls.TStyle'); + +/** + * TPanelStyle class. + * TPanelStyle represents the CSS style specific for panel HTML tag. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TPanelStyle extends TStyle +{ + /** + * @var string the URL of the background image for the panel component + */ + private $_backImageUrl=null; + /** + * @var string alignment of the content in the panel. + */ + private $_direction=null; + /** + * @var string horizontal alignment of the contents within the panel + */ + private $_horizontalAlign=null; + /** + * @var string visibility and position of scroll bars + */ + private $_scrollBars=null; + /** + * @var boolean whether the content wraps within the panel + */ + private $_wrap=null; + + /** + * Adds attributes related to CSS styles to renderer. + * This method overrides the parent implementation. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if(($url=trim($this->getBackImageUrl()))!=='') + $this->setStyleField('background-image','url('.$url.')'); + + switch($this->getScrollBars()) + { + case TScrollBars::Horizontal: $this->setStyleField('overflow-x','scroll'); break; + case TScrollBars::Vertical: $this->setStyleField('overflow-y','scroll'); break; + case TScrollBars::Both: $this->setStyleField('overflow','scroll'); break; + case TScrollBars::Auto: $this->setStyleField('overflow','auto'); break; + } + + if(($align=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) + $this->setStyleField('text-align',strtolower($align)); + + if(!$this->getWrap()) + $this->setStyleField('white-space','nowrap'); + + if(($direction=$this->getDirection())!==TContentDirection::NotSet) + { + if($direction===TContentDirection::LeftToRight) + $this->setStyleField('direction','ltr'); + else + $this->setStyleField('direction','rtl'); + } + + parent::addAttributesToRender($writer); + } + + /** + * @return string the URL of the background image for the panel component. + */ + public function getBackImageUrl() + { + return $this->_backImageUrl===null?'':$this->_backImageUrl; + } + + /** + * Sets the URL of the background image for the panel component. + * @param string the URL + */ + public function setBackImageUrl($value) + { + $this->_backImageUrl=$value; + } + + /** + * @return TContentDirection alignment of the content in the panel. Defaults to TContentDirection::NotSet. + */ + public function getDirection() + { + return $this->_direction===null?TContentDirection::NotSet:$this->_direction; + } + + /** + * @param TContentDirection alignment of the content in the panel. + */ + public function setDirection($value) + { + $this->_direction=TPropertyValue::ensureEnum($value,'TContentDirection'); + } + + /** + * @return boolean whether the content wraps within the panel. Defaults to true. + */ + public function getWrap() + { + return $this->_wrap===null?true:$this->_wrap; + } + + /** + * Sets the value indicating whether the content wraps within the panel. + * @param boolean whether the content wraps within the panel. + */ + public function setWrap($value) + { + $this->_wrap=TPropertyValue::ensureBoolean($value); + } + + /** + * @return THorizontalAlign the horizontal alignment of the contents within the panel, defaults to THorizontalAlign::NotSet. + */ + public function getHorizontalAlign() + { + return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; + } + + /** + * Sets the horizontal alignment of the contents within the panel. + * @param THorizontalAlign the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); + } + + /** + * @return TScrollBars the visibility and position of scroll bars in a panel control, defaults to TScrollBars::None. + */ + public function getScrollBars() + { + return $this->_scrollBars===null?TScrollBars::None:$this->_scrollBars; + } + + /** + * @param TScrollBars the visibility and position of scroll bars in a panel control. + */ + public function setScrollBars($value) + { + $this->_scrollBars=TPropertyValue::ensureEnum($value,'TScrollBars'); + } + + /** + * Sets the style attributes to default values. + * This method overrides the parent implementation by + * resetting additional TPanelStyle specific attributes. + */ + public function reset() + { + parent::reset(); + $this->_backImageUrl=null; + $this->_direction=null; + $this->_horizontalAlign=null; + $this->_scrollBars=null; + $this->_wrap=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TPanelStyle) + { + if($style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($style->_direction!==null) + $this->_direction=$style->_direction; + if($style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($style->_scrollBars!==null) + $this->_scrollBars=$style->_scrollBars; + if($style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TPanelStyle) + { + if($this->_backImageUrl===null && $style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($this->_direction===null && $style->_direction!==null) + $this->_direction=$style->_direction; + if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($this->_scrollBars===null && $style->_scrollBars!==null) + $this->_scrollBars=$style->_scrollBars; + if($this->_wrap===null && $style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } +} + +/** + * TContentDirection class. + * TContentDirection defines the enumerable type for the possible directions that a panel can be at. + * + * The following enumerable values are defined: + * - NotSet: the direction is not specified + * - LeftToRight: content in a panel is left to right + * - RightToLeft: content in a panel is right to left + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TContentDirection extends TEnumerable +{ + const NotSet='NotSet'; + const LeftToRight='LeftToRight'; + const RightToLeft='RightToLeft'; +} + +/** + * TScrollBars class. + * TScrollBars defines the enumerable type for the possible scroll bar mode + * that a {@link TPanel} control could use. + * + * The following enumerable values are defined: + * - None: no scroll bars. + * - Auto: scroll bars automatically appeared when needed. + * - Both: show both horizontal and vertical scroll bars all the time. + * - Horizontal: horizontal scroll bar only + * - Vertical: vertical scroll bar only + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TScrollBars extends TEnumerable +{ + const None='None'; + const Auto='Auto'; + const Both='Both'; + const Horizontal='Horizontal'; + const Vertical='Vertical'; +} + diff --git a/framework/Web/UI/WebControls/TPlaceHolder.php b/framework/Web/UI/WebControls/TPlaceHolder.php index ac67cef7..585e9e99 100644 --- a/framework/Web/UI/WebControls/TPlaceHolder.php +++ b/framework/Web/UI/WebControls/TPlaceHolder.php @@ -1,28 +1,28 @@ -<?php
-/**
- * TPlaceHolder class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TPlaceHolder class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TPlaceHolder class
- *
- * TPlaceHolder reserves a place on a template, where static texts or controls
- * may be inserted. You may add or remove texts or child controls of TPlaceHolder
- * by manipulating the {@link TControl::getControls Controls} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPlaceHolder extends TControl
-{
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TPlaceHolder class + * + * TPlaceHolder reserves a place on a template, where static texts or controls + * may be inserted. You may add or remove texts or child controls of TPlaceHolder + * by manipulating the {@link TControl::getControls Controls} property. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TPlaceHolder extends TControl +{ +} + diff --git a/framework/Web/UI/WebControls/TRadioButton.php b/framework/Web/UI/WebControls/TRadioButton.php index b90cfcf5..6a2347f4 100644 --- a/framework/Web/UI/WebControls/TRadioButton.php +++ b/framework/Web/UI/WebControls/TRadioButton.php @@ -1,320 +1,320 @@ -<?php
-/**
- * TRadioButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TRadioButton class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TCheckBox parent class
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-/**
- * Using TRadioButtonList class
- */
-Prado::using('System.Web.UI.WebControls.TRadioButtonList');
-
-/**
- * TRadioButton class
- *
- * TRadioButton displays a radio button on the page.
- * You can specify the caption to display beside the radio buttonby setting
- * the {@link setText Text} property. The caption can appear either on the right
- * or left of the radio button, which is determined by the {@link setTextAlign TextAlign}
- * property.
- *
- * To determine whether the TRadioButton component is checked, test the {@link getChecked Checked}
- * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
- * the {@link getChecked Checked} state of the TRadioButton component changes
- * between posts to the server. You can provide an event handler for
- * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
- * control the actions performed when the state of the TRadioButton component changes
- * between posts to the server.
- *
- * TRadioButton uses {@link setGroupName GroupName} to group together a set of radio buttons.
- * Once the {@link setGroupName GroupName} is set, you can use the {@link getRadioButtonsInGroup}
- * method to get an array of TRadioButtons having the same group name.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, changing the radio button state
- * will cause postback action. And if {@link setCausesValidation CausesValidation}
- * is true, validation will also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
- * that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRadioButton extends TCheckBox
-{
- /**
- * @param array list of radio buttons that are on the current page hierarchy
- */
- private static $_activeButtons=array();
- /**
- * @var integer number of radio buttons created
- */
- private static $_buttonCount=0;
- /**
- * @var integer global ID of this radiobutton
- */
- private $_globalID;
- /**
- * @var string previous UniqueID (used to calculate UniqueGroup)
- */
- private $_previousUniqueID=null;
- /**
- * @var string the name used to fetch radiobutton post data
- */
- private $_uniqueGroupName=null;
-
- /**
- * Constructor.
- * Registers the radiobutton in a global radiobutton collection.
- * If overridden, the parent implementation must be invoked first.
- */
- public function __construct()
- {
- parent::__construct();
- $this->_globalID = self::$_buttonCount++;
- }
-
- /**
- * Registers the radio button groupings. If overriding onInit method,
- * ensure to call parent implemenation.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- parent::onInit($param);
- self::$_activeButtons[$this->_globalID]=$this;
- }
-
- /**
- * Unregisters the radio button groupings. If overriding onInit method,
- * ensure to call parent implemenation.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnLoad($param)
- {
- unset(self::$_activeButtons[$this->_globalID]);
- parent::onUnLoad($param);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- $uniqueGroupName=$this->getUniqueGroupName();
- $value=isset($values[$uniqueGroupName])?$values[$uniqueGroupName]:null;
- if($value!==null && $value===$this->getValueAttribute())
- {
- if(!$this->getChecked())
- {
- $this->setChecked(true);
- return true;
- }
- else
- return false;
- }
- else if($this->getChecked())
- $this->setChecked(false);
- return false;
- }
-
- /**
- * @return string the name of the group that the radio button belongs to. Defaults to empty.
- */
- public function getGroupName()
- {
- return $this->getViewState('GroupName','');
- }
-
- /**
- * Sets the name of the group that the radio button belongs to.
- * The group is unique among the control's naming container.
- * @param string the group name
- * @see setUniqueGroupName
- */
- public function setGroupName($value)
- {
- $this->setViewState('GroupName',$value,'');
- $this->_uniqueGroupName=null;
- }
-
- /**
- * Add the group name as post data loader if group name is set.
- */
- protected function addToPostDataLoader()
- {
- parent::addToPostDataLoader();
- $group = $this->getGroupName();
- if(!empty($group) || $this->getViewState('UniqueGroupName','') !== '')
- $this->getPage()->registerPostDataLoader($this->getUniqueGroupName());
- }
- /**
- * @return string the name used to fetch radiobutton post data
- */
- public function getUniqueGroupName()
- {
- if(($groupName=$this->getViewState('UniqueGroupName',''))!=='')
- return $groupName;
- else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null)
- {
- $groupName=$this->getGroupName();
- $this->_previousUniqueID=$uniqueID;
- if($uniqueID!=='')
- {
- if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false)
- {
- if($groupName!=='')
- $groupName=substr($uniqueID,0,$pos+1).$groupName;
- else if($this->getNamingContainer() instanceof TRadioButtonList)
- $groupName=substr($uniqueID,0,$pos);
- }
- if($groupName==='')
- $groupName=$uniqueID;
- }
- $this->_uniqueGroupName=$groupName;
- }
- return $this->_uniqueGroupName;
- }
-
- /**
- * Sets the unique group name that the radio button belongs to.
- * A unique group is a radiobutton group unique among the whole page hierarchy,
- * while the {@link setGroupName GroupName} specifies a group that is unique
- * among the control's naming container only.
- * For example, each cell of a {@link TDataGrid} is a naming container.
- * If you specify {@link setGroupName GroupName} for a radiobutton in a cell,
- * it groups together radiobutton within a cell, but not the other, even though
- * they have the same {@link setGroupName GroupName}.
- * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead,
- * it will group all appropriate radio buttons on the whole page hierarchy.
- * Note, when both {@link setUniqueGroupName UniqueGroupName} and
- * {@link setGroupName GroupName}, the former takes precedence.
- * @param string the group name
- * @see setGroupName
- */
- public function setUniqueGroupName($value)
- {
- $this->setViewState('UniqueGroupName',$value,'');
- }
-
- /**
- * Gets an array of radiobuttons whose group name is the same as this radiobutton's.
- * Note, only those radiobuttons that are on the current page hierarchy may be
- * returned in the result.
- * @return array list of TRadioButton with the same group
- */
- public function getRadioButtonsInGroup()
- {
- $group = $this->getUniqueGroupName();
- $buttons = array();
- foreach(self::$_activeButtons as $control)
- {
- if($control->getUniqueGroupName() === $group)
- $buttons[] = $control;
- }
- return $buttons;
- }
-
- /**
- * @return string the value attribute to be rendered
- */
- protected function getValueAttribute()
- {
- if(($value=parent::getValueAttribute())==='')
- return $this->getUniqueID();
- else
- return $value;
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Renders a radiobutton input element.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string onclick js
- */
- protected function renderInputTag($writer,$clientID,$onclick)
- {
- if($clientID!=='')
- $writer->addAttribute('id',$clientID);
- $writer->addAttribute('type','radio');
- $writer->addAttribute('name',$this->getUniqueGroupName());
- $writer->addAttribute('value',$this->getValueAttribute());
- if(!empty($onclick))
- $writer->addAttribute('onclick',$onclick);
- if($this->getChecked())
- $writer->addAttribute('checked','checked');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
-
- $page=$this->getPage();
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
-
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- if(($tabindex=$this->getTabIndex())>0)
- $writer->addAttribute('tabindex',"$tabindex");
- if($attributes=$this->getViewState('InputAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRadioButton';
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TCheckBox parent class + */ +Prado::using('System.Web.UI.WebControls.TCheckBox'); +/** + * Using TRadioButtonList class + */ +Prado::using('System.Web.UI.WebControls.TRadioButtonList'); + +/** + * TRadioButton class + * + * TRadioButton displays a radio button on the page. + * You can specify the caption to display beside the radio buttonby setting + * the {@link setText Text} property. The caption can appear either on the right + * or left of the radio button, which is determined by the {@link setTextAlign TextAlign} + * property. + * + * To determine whether the TRadioButton component is checked, test the {@link getChecked Checked} + * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when + * the {@link getChecked Checked} state of the TRadioButton component changes + * between posts to the server. You can provide an event handler for + * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically + * control the actions performed when the state of the TRadioButton component changes + * between posts to the server. + * + * TRadioButton uses {@link setGroupName GroupName} to group together a set of radio buttons. + * Once the {@link setGroupName GroupName} is set, you can use the {@link getRadioButtonsInGroup} + * method to get an array of TRadioButtons having the same group name. + * + * If {@link setAutoPostBack AutoPostBack} is set true, changing the radio button state + * will cause postback action. And if {@link setCausesValidation CausesValidation} + * is true, validation will also be processed, which can be further restricted within + * a {@link setValidationGroup ValidationGroup}. + * + * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters + * that may bring security vulnerabilities. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRadioButton extends TCheckBox +{ + /** + * @param array list of radio buttons that are on the current page hierarchy + */ + private static $_activeButtons=array(); + /** + * @var integer number of radio buttons created + */ + private static $_buttonCount=0; + /** + * @var integer global ID of this radiobutton + */ + private $_globalID; + /** + * @var string previous UniqueID (used to calculate UniqueGroup) + */ + private $_previousUniqueID=null; + /** + * @var string the name used to fetch radiobutton post data + */ + private $_uniqueGroupName=null; + + /** + * Constructor. + * Registers the radiobutton in a global radiobutton collection. + * If overridden, the parent implementation must be invoked first. + */ + public function __construct() + { + parent::__construct(); + $this->_globalID = self::$_buttonCount++; + } + + /** + * Registers the radio button groupings. If overriding onInit method, + * ensure to call parent implemenation. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onInit($param) + { + parent::onInit($param); + self::$_activeButtons[$this->_globalID]=$this; + } + + /** + * Unregisters the radio button groupings. If overriding onInit method, + * ensure to call parent implemenation. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onUnLoad($param) + { + unset(self::$_activeButtons[$this->_globalID]); + parent::onUnLoad($param); + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the control has been changed + */ + public function loadPostData($key,$values) + { + $uniqueGroupName=$this->getUniqueGroupName(); + $value=isset($values[$uniqueGroupName])?$values[$uniqueGroupName]:null; + if($value!==null && $value===$this->getValueAttribute()) + { + if(!$this->getChecked()) + { + $this->setChecked(true); + return true; + } + else + return false; + } + else if($this->getChecked()) + $this->setChecked(false); + return false; + } + + /** + * @return string the name of the group that the radio button belongs to. Defaults to empty. + */ + public function getGroupName() + { + return $this->getViewState('GroupName',''); + } + + /** + * Sets the name of the group that the radio button belongs to. + * The group is unique among the control's naming container. + * @param string the group name + * @see setUniqueGroupName + */ + public function setGroupName($value) + { + $this->setViewState('GroupName',$value,''); + $this->_uniqueGroupName=null; + } + + /** + * Add the group name as post data loader if group name is set. + */ + protected function addToPostDataLoader() + { + parent::addToPostDataLoader(); + $group = $this->getGroupName(); + if(!empty($group) || $this->getViewState('UniqueGroupName','') !== '') + $this->getPage()->registerPostDataLoader($this->getUniqueGroupName()); + } + /** + * @return string the name used to fetch radiobutton post data + */ + public function getUniqueGroupName() + { + if(($groupName=$this->getViewState('UniqueGroupName',''))!=='') + return $groupName; + else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null) + { + $groupName=$this->getGroupName(); + $this->_previousUniqueID=$uniqueID; + if($uniqueID!=='') + { + if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false) + { + if($groupName!=='') + $groupName=substr($uniqueID,0,$pos+1).$groupName; + else if($this->getNamingContainer() instanceof TRadioButtonList) + $groupName=substr($uniqueID,0,$pos); + } + if($groupName==='') + $groupName=$uniqueID; + } + $this->_uniqueGroupName=$groupName; + } + return $this->_uniqueGroupName; + } + + /** + * Sets the unique group name that the radio button belongs to. + * A unique group is a radiobutton group unique among the whole page hierarchy, + * while the {@link setGroupName GroupName} specifies a group that is unique + * among the control's naming container only. + * For example, each cell of a {@link TDataGrid} is a naming container. + * If you specify {@link setGroupName GroupName} for a radiobutton in a cell, + * it groups together radiobutton within a cell, but not the other, even though + * they have the same {@link setGroupName GroupName}. + * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead, + * it will group all appropriate radio buttons on the whole page hierarchy. + * Note, when both {@link setUniqueGroupName UniqueGroupName} and + * {@link setGroupName GroupName}, the former takes precedence. + * @param string the group name + * @see setGroupName + */ + public function setUniqueGroupName($value) + { + $this->setViewState('UniqueGroupName',$value,''); + } + + /** + * Gets an array of radiobuttons whose group name is the same as this radiobutton's. + * Note, only those radiobuttons that are on the current page hierarchy may be + * returned in the result. + * @return array list of TRadioButton with the same group + */ + public function getRadioButtonsInGroup() + { + $group = $this->getUniqueGroupName(); + $buttons = array(); + foreach(self::$_activeButtons as $control) + { + if($control->getUniqueGroupName() === $group) + $buttons[] = $control; + } + return $buttons; + } + + /** + * @return string the value attribute to be rendered + */ + protected function getValueAttribute() + { + if(($value=parent::getValueAttribute())==='') + return $this->getUniqueID(); + else + return $value; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Renders a radiobutton input element. + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string onclick js + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + if($clientID!=='') + $writer->addAttribute('id',$clientID); + $writer->addAttribute('type','radio'); + $writer->addAttribute('name',$this->getUniqueGroupName()); + $writer->addAttribute('value',$this->getValueAttribute()); + if(!empty($onclick)) + $writer->addAttribute('onclick',$onclick); + if($this->getChecked()) + $writer->addAttribute('checked','checked'); + if(!$this->getEnabled(true)) + $writer->addAttribute('disabled','disabled'); + + $page=$this->getPage(); + if($this->getEnabled(true) + && $this->getEnableClientScript() + && $this->getAutoPostBack() + && $page->getClientSupportsJavaScript()) + { + $this->renderClientControlScript($writer); + } + + if(($accesskey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accesskey); + if(($tabindex=$this->getTabIndex())>0) + $writer->addAttribute('tabindex',"$tabindex"); + if($attributes=$this->getViewState('InputAttributes',null)) + $writer->addAttributes($attributes); + $writer->renderBeginTag('input'); + $writer->renderEndTag(); + } + + /** + * Renders the client-script code. + */ + protected function renderClientControlScript($writer) + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TRadioButton'; + } +} + diff --git a/framework/Web/UI/WebControls/TRangeValidator.php b/framework/Web/UI/WebControls/TRangeValidator.php index d8d2d20d..57538e88 100644 --- a/framework/Web/UI/WebControls/TRangeValidator.php +++ b/framework/Web/UI/WebControls/TRangeValidator.php @@ -1,360 +1,360 @@ -<?php
-/**
- * TRangeValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TRangeValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRangeValidator class
- *
- * TRangeValidator tests whether an input value is within a specified range.
- *
- * TRangeValidator uses three key properties to perform its validation.
- * The {@link setMinValue MinValue} and {@link setMaxValue MaxValue}
- * properties specify the minimum and maximum values of the valid range.
- * The {@link setDataType DataType} property is used to specify the
- * data type of the value and the minimum and maximum range values.
- * These values are converted to this data type before the validation
- * operation is performed. The following value types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type. The date format can be specified by
- * setting {@link setDateFormat DateFormat} property, which must be recognizable
- * by {@link TSimpleDateFormatter}. If the property is not set,
- * the GNU date syntax is assumed.
- * - <b>String</b> A string data type.
- * - <b>StringLength</b> check for string length.
- *
- * If {@link setStrictComparison StrictComparison} is true, then the ranges
- * are compared as strictly less than the max value and/or strictly greater than the min value.
- *
- * The TRangeValidator allows a special DataType "StringLength" that
- * can be used to verify minimum and maximum string length. The
- * {@link setCharset Charset} property can be used to force a particular
- * charset for comparison. Otherwise, the application charset is used and is
- * defaulted as UTF-8.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRangeValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRangeValidator';
- }
-
- /**
- * @return string the minimum value of the validation range.
- */
- public function getMinValue()
- {
- return $this->getViewState('MinValue','');
- }
-
- /**
- * Sets the minimum value of the validation range.
- * @param string the minimum value
- */
- public function setMinValue($value)
- {
- $this->setViewState('MinValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the maximum value of the validation range.
- */
- public function getMaxValue()
- {
- return $this->getViewState('MaxValue','');
- }
-
- /**
- * Sets the maximum value of the validation range.
- * @param string the maximum value
- */
- public function setMaxValue($value)
- {
- $this->setViewState('MaxValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @param boolean true to perform strict comparison (i.e. strictly less than max and/or strictly greater than min).
- */
- public function setStrictComparison($value)
- {
- $this->setViewState('StrictComparison', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true to perform strict comparison.
- */
- public function getStrictComparison()
- {
- return $this->getViewState('StrictComparison', false);
- }
-
- /**
- * @return TRangeValidationDataType the data type that the values being compared are
- * converted to before the comparison is made. Defaults to TRangeValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType',TRangeValidationDataType::String);
- }
-
- /**
- * Sets the data type that the values being compared are converted to before the comparison is made.
- * @param TRangeValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TRangeValidationDataType'),TRangeValidationDataType::String);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
- /**
- * @param string charset for string length comparison.
- */
- public function setCharset($value)
- {
- $this->setViewState('Charset', $value, '');
- }
-
- /**
- * @return string charset for string length comparison.
- */
- public function getCharset()
- {
- return $this->getViewState('Charset', '');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data is within the range.
- * The validation always succeeds if the input data is empty.
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $value=$this->getValidationValue($this->getValidationTarget());
- if($value==='')
- return true;
-
- switch($this->getDataType())
- {
- case TRangeValidationDataType::Integer:
- return $this->isValidInteger($value);
- case TRangeValidationDataType::Float:
- return $this->isValidFloat($value);
- case TRangeValidationDataType::Date:
- return $this->isValidDate($value);
- case TRangeValidationDataType::StringLength:
- return $this->isValidStringLength($value);
- default:
- return $this->isValidString($value);
- }
- }
-
- /**
- * Determine if the value is within the integer range.
- * @param string value to validate true
- * @return boolean true if within integer range.
- */
- protected function isValidInteger($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TRangeValidator class + * + * TRangeValidator tests whether an input value is within a specified range. + * + * TRangeValidator uses three key properties to perform its validation. + * The {@link setMinValue MinValue} and {@link setMaxValue MaxValue} + * properties specify the minimum and maximum values of the valid range. + * The {@link setDataType DataType} property is used to specify the + * data type of the value and the minimum and maximum range values. + * These values are converted to this data type before the validation + * operation is performed. The following value types are supported: + * - <b>Integer</b> A 32-bit signed integer data type. + * - <b>Float</b> A double-precision floating point number data type. + * - <b>Date</b> A date data type. The date format can be specified by + * setting {@link setDateFormat DateFormat} property, which must be recognizable + * by {@link TSimpleDateFormatter}. If the property is not set, + * the GNU date syntax is assumed. + * - <b>String</b> A string data type. + * - <b>StringLength</b> check for string length. + * + * If {@link setStrictComparison StrictComparison} is true, then the ranges + * are compared as strictly less than the max value and/or strictly greater than the min value. + * + * The TRangeValidator allows a special DataType "StringLength" that + * can be used to verify minimum and maximum string length. The + * {@link setCharset Charset} property can be used to force a particular + * charset for comparison. Otherwise, the application charset is used and is + * defaulted as UTF-8. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRangeValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TRangeValidator'; + } + + /** + * @return string the minimum value of the validation range. + */ + public function getMinValue() + { + return $this->getViewState('MinValue',''); + } + + /** + * Sets the minimum value of the validation range. + * @param string the minimum value + */ + public function setMinValue($value) + { + $this->setViewState('MinValue',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the maximum value of the validation range. + */ + public function getMaxValue() + { + return $this->getViewState('MaxValue',''); + } + + /** + * Sets the maximum value of the validation range. + * @param string the maximum value + */ + public function setMaxValue($value) + { + $this->setViewState('MaxValue',TPropertyValue::ensureString($value),''); + } + + /** + * @param boolean true to perform strict comparison (i.e. strictly less than max and/or strictly greater than min). + */ + public function setStrictComparison($value) + { + $this->setViewState('StrictComparison', TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean true to perform strict comparison. + */ + public function getStrictComparison() + { + return $this->getViewState('StrictComparison', false); + } + + /** + * @return TRangeValidationDataType the data type that the values being compared are + * converted to before the comparison is made. Defaults to TRangeValidationDataType::String. + */ + public function getDataType() + { + return $this->getViewState('DataType',TRangeValidationDataType::String); + } + + /** + * Sets the data type that the values being compared are converted to before the comparison is made. + * @param TRangeValidationDataType the data type + */ + public function setDataType($value) + { + $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TRangeValidationDataType'),TRangeValidationDataType::String); + } + + /** + * Sets the date format for a date validation + * @param string the date format value + */ + public function setDateFormat($value) + { + $this->setViewState('DateFormat', $value, ''); + } + + /** + * @return string the date validation date format if any + */ + public function getDateFormat() + { + return $this->getViewState('DateFormat', ''); + } + + /** + * @param string charset for string length comparison. + */ + public function setCharset($value) + { + $this->setViewState('Charset', $value, ''); + } + + /** + * @return string charset for string length comparison. + */ + public function getCharset() + { + return $this->getViewState('Charset', ''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input data is within the range. + * The validation always succeeds if the input data is empty. + * @return boolean whether the validation succeeds + */ + protected function evaluateIsValid() + { + $value=$this->getValidationValue($this->getValidationTarget()); + if($value==='') + return true; + + switch($this->getDataType()) + { + case TRangeValidationDataType::Integer: + return $this->isValidInteger($value); + case TRangeValidationDataType::Float: + return $this->isValidFloat($value); + case TRangeValidationDataType::Date: + return $this->isValidDate($value); + case TRangeValidationDataType::StringLength: + return $this->isValidStringLength($value); + default: + return $this->isValidString($value); + } + } + + /** + * Determine if the value is within the integer range. + * @param string value to validate true + * @return boolean true if within integer range. + */ + protected function isValidInteger($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + $valid=preg_match('/^[-+]?[0-9]+$/',trim($value)); - $value=intval($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value, intval($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,intval($maxValue));
- return $valid;
- }
-
- protected function isLessThan($left,$right)
- {
- return $this->getStrictComparison() ? $left < $right : $left <= $right;
- }
-
- protected function isGreaterThan($left, $right)
- {
- return $this->getStrictComparison() ? $left > $right : $left >= $right;
- }
-
- /**
- * Determine if the value is within the specified float range.
- * @param string value to validate
- * @return boolean true if within range.
- */
- protected function isValidFloat($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
- - $valid=preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
- $value=floatval($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,floatval($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,floatval($maxValue));
- return $valid;
- }
-
- /**
- * Determine if the date is within the specified range.
- * Uses pradoParseDate and strtotime to get the date from string.
- * @param string date as string to validate
- * @return boolean true if within range.
- */
- protected function isValidDate($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
-
- $dateFormat = $this->getDateFormat();
- if($dateFormat!=='')
- {
- $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
- $value = $formatter->parse($value, $dateFormat);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,$formatter->parse($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,$formatter->parse($maxValue));
- return $valid;
- }
- else
- {
- $value=strtotime($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,strtotime($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,strtotime($maxValue));
- return $valid;
- }
- }
-
- /**
- * Compare the string with a minimum and a maxiumum value.
- * Uses strcmp for comparision.
- * @param string value to compare with.
- * @return boolean true if the string is within range.
- */
- protected function isValidString($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan(strcmp($value,$minValue),0);
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan(strcmp($value,$maxValue),0);
- return $valid;
- }
-
- /**
- * @param string string for comparision
- * @return boolean true if min and max string length are satisfied.
- */
- protected function isValidStringLength($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
- $charset = $this->getCharset();
- if($charset==='')
- {
- $app= $this->getApplication()->getGlobalization();
- $charset = $app ? $app->getCharset() : null;
- if(!$charset)
- $charset = 'UTF-8';
- }
-
- $length = iconv_strlen($value, $charset);
- if($minValue!=='')
- $valid = $valid && $this->isGreaterThan($length,intval($minValue));
- if($maxValue!=='')
- $valid = $valid && $this->isLessThan($length,intval($maxValue));
- return $valid;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- $options['MinValue']=$this->getMinValue();
- $options['MaxValue']=$this->getMaxValue();
- $options['DataType']=$this->getDataType();
- $options['StrictComparison']=$this->getStrictComparison();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-}
-
-
-/**
- * TRangeValidationDataType class.
- * TRangeValidationDataType defines the enumerable type for the possible data types that
- * a range validator can validate upon.
- *
- * The following enumerable values are defined:
- * - Integer
- * - Float
- * - Date
- * - String
- * - StringLength
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRangeValidationDataType extends TValidationDataType
-{
- const StringLength='StringLength';
-}
+ $value=intval($value); + if($minValue!=='') + $valid=$valid && $this->isGreaterThan($value, intval($minValue)); + if($maxValue!=='') + $valid=$valid && $this->isLessThan($value,intval($maxValue)); + return $valid; + } + + protected function isLessThan($left,$right) + { + return $this->getStrictComparison() ? $left < $right : $left <= $right; + } + + protected function isGreaterThan($left, $right) + { + return $this->getStrictComparison() ? $left > $right : $left >= $right; + } + + /** + * Determine if the value is within the specified float range. + * @param string value to validate + * @return boolean true if within range. + */ + protected function isValidFloat($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + + $valid=preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value)); + $value=floatval($value); + if($minValue!=='') + $valid=$valid && $this->isGreaterThan($value,floatval($minValue)); + if($maxValue!=='') + $valid=$valid && $this->isLessThan($value,floatval($maxValue)); + return $valid; + } + + /** + * Determine if the date is within the specified range. + * Uses pradoParseDate and strtotime to get the date from string. + * @param string date as string to validate + * @return boolean true if within range. + */ + protected function isValidDate($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + + $valid=true; + + $dateFormat = $this->getDateFormat(); + if($dateFormat!=='') + { + $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat); + $value = $formatter->parse($value, $dateFormat); + if($minValue!=='') + $valid=$valid && $this->isGreaterThan($value,$formatter->parse($minValue)); + if($maxValue!=='') + $valid=$valid && $this->isLessThan($value,$formatter->parse($maxValue)); + return $valid; + } + else + { + $value=strtotime($value); + if($minValue!=='') + $valid=$valid && $this->isGreaterThan($value,strtotime($minValue)); + if($maxValue!=='') + $valid=$valid && $this->isLessThan($value,strtotime($maxValue)); + return $valid; + } + } + + /** + * Compare the string with a minimum and a maxiumum value. + * Uses strcmp for comparision. + * @param string value to compare with. + * @return boolean true if the string is within range. + */ + protected function isValidString($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + + $valid=true; + if($minValue!=='') + $valid=$valid && $this->isGreaterThan(strcmp($value,$minValue),0); + if($maxValue!=='') + $valid=$valid && $this->isLessThan(strcmp($value,$maxValue),0); + return $valid; + } + + /** + * @param string string for comparision + * @return boolean true if min and max string length are satisfied. + */ + protected function isValidStringLength($value) + { + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + + $valid=true; + $charset = $this->getCharset(); + if($charset==='') + { + $app= $this->getApplication()->getGlobalization(); + $charset = $app ? $app->getCharset() : null; + if(!$charset) + $charset = 'UTF-8'; + } + + $length = iconv_strlen($value, $charset); + if($minValue!=='') + $valid = $valid && $this->isGreaterThan($length,intval($minValue)); + if($maxValue!=='') + $valid = $valid && $this->isLessThan($length,intval($maxValue)); + return $valid; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options=parent::getClientScriptOptions(); + $options['MinValue']=$this->getMinValue(); + $options['MaxValue']=$this->getMaxValue(); + $options['DataType']=$this->getDataType(); + $options['StrictComparison']=$this->getStrictComparison(); + if(($dateFormat=$this->getDateFormat())!=='') + $options['DateFormat']=$dateFormat; + return $options; + } +} + + +/** + * TRangeValidationDataType class. + * TRangeValidationDataType defines the enumerable type for the possible data types that + * a range validator can validate upon. + * + * The following enumerable values are defined: + * - Integer + * - Float + * - Date + * - String + * - StringLength + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TRangeValidationDataType extends TValidationDataType +{ + const StringLength='StringLength'; +} diff --git a/framework/Web/UI/WebControls/TRatingList.php b/framework/Web/UI/WebControls/TRatingList.php index dfb11371..cc813755 100644 --- a/framework/Web/UI/WebControls/TRatingList.php +++ b/framework/Web/UI/WebControls/TRatingList.php @@ -1,359 +1,359 @@ -<?php
-/**
- * TRatingList class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TRadioButtonList class
- */
-Prado::using('System.Web.UI.WebControls.TRadioButtonList');
-
-/**
- * TRatingList class.
- *
- * This class is EXPERIMENTAL.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRatingList extends TRadioButtonList
-{
- /**
- * Script path relative to the TClientScriptManager::SCRIPT_PATH
- */
- const SCRIPT_PATH='prado/ratings';
-
- /**
- * @var array list of published rating images.
- */
- private $_ratingImages = array();
-
- /**
- * Sets the default repeat direction to horizontal.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setRepeatDirection(TRepeatDirection::Horizontal);
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @return boolean whether the rating list can be edited. Defaults to true.
- */
- public function getAllowInput()
- {
- return !$this->getReadOnly();
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @param boolean whether the rating list can be edited
- */
- public function setAllowInput($value)
- {
- $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @param boolean whether the rating list can be edited
- */
- public function setEnabled($value)
- {
- $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * The repeat layout must be Table.
- * @param string repeat layout type
- * @throws TInvaliddataValueException when repeat layout is not Table.
- */
- public function setRepeatLayout($value)
- {
- if($value!==TRepeatLayout::Table)
- throw new TInvalidDataValueException('ratinglist_table_layout_only');
- else
- parent::setRepeatLayout($value);
- }
-
- /**
- * @return float rating value.
- */
- public function getRating()
- {
- $rating = $this->getViewState('Rating', null);
- if ($rating === null)
- return $this->getSelectedIndex()+1;
- else
- return $rating;
- }
-
- /**
- * @param float rating value, also sets the selected Index
- */
- public function setRating($value)
- {
- $value = TPropertyValue::ensureFloat($value);
- $this->setViewState('Rating', $value, null);
- $index = $this->getRatingIndex($value);
- parent::setSelectedIndex($index);
- }
-
- public function setSelectedIndex($value)
- {
- $this->setRating($value+1);
- parent::setSelectedIndex($value);
- }
-
- /**
- * @param float rating value
- * @return int rating as integer
- */
- protected function getRatingIndex($rating)
- {
- $interval = $this->getHalfRatingInterval();
- $base = intval($rating)-1;
- $remainder = $rating-$base-1;
- return $remainder > $interval[1] ? $base+1 : $base;
- }
-
- /**
- * @param int change the rating selection index
- */
- public function onSelectedIndexChanged($param)
- {
- $value = $this->getRating();
- $value = TPropertyValue::ensureInteger($value);
- $this->setRating($value);
- parent::onSelectedIndexChanged($param);
- }
-
- /**
- * @return string control or html element ID for displaying a caption.
- */
- public function getCaptionID()
- {
- return $this->getViewState('CaptionID', '');
- }
-
- /**
- * @param string control or html element ID for displaying a caption.
- */
- public function setCaptionID($value)
- {
- $this->setViewState('CaptionID', $value, '');
- }
-
- protected function getCaptionControl()
- {
- if(($id=$this->getCaptionID())!=='')
- {
- if($control=$this->getParent()->findControl($id))
- return $control;
- }
- throw new TInvalidDataValueException(
- 'ratinglist_invalid_caption_id',$id,$this->getID());
- }
-
- /**
- * @return string caption text. Default is "Rate It:".
- */
- public function getCaption()
- {
- return $this->getCaptionControl()->getText();
- }
-
- /**
- * @return TRatingListStyle current rating style
- */
- public function setCaption($value)
- {
- $this->getCaptionControl()->setText($value);
- }
-
- /**
- * @param string set the rating style, default is "default"
- */
- public function setRatingStyle($value)
- {
- $this->setViewState('RatingStyle', $value, 'default');
- }
-
- /**
- * @return TRatingListStyle current rating style
- */
- public function getRatingStyle()
- {
- return $this->getViewState('RatingStyle', 'default');
- }
-
- /**
- * @return string rating style css class name.
- */
- protected function getRatingStyleCssClass()
- {
- return 'TRatingList_'.$this->getRatingStyle();
- }
-
- /**
- * Sets the interval such that those rating values within the interval
- * will be considered as a half star rating.
- * @param array rating display half value interval, default is array(0.3, 0.7);
- */
- public function setHalfRatingInterval($value)
- {
- $this->setViewState('HalfRating',
- TPropertyValue::ensureArray($value), array(0.3, 0.7));
- }
-
- /**
- * @return array rating display half value interval, default is array(0.3, 0.7);
- */
- public function getHalfRatingInterval()
- {
- return $this->getViewState('HalfRating', array(0.3, 0.7));
- }
-
- /**
- * @return array list of post back options.
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['AutoPostBack'] = $this->getAutoPostBack();
- $options['ReadOnly'] = $this->getReadOnly();
- $options['Style'] = $this->getRatingStyleCssClass();
- $options['CaptionID'] = $this->getCaptionControlID();
- $options['SelectedIndex'] = $this->getSelectedIndex();
- $options['Rating'] = $this->getRating();
- $options['HalfRating'] = $this->getHalfRatingInterval();
- return $options;
- }
-
- /**
- * @return string find the client ID of the caption control.
- */
- protected function getCaptionControlID()
- {
- if(($id=$this->getCaptionID())!=='')
- {
- if($control=$this->getParent()->findControl($id))
- {
- if($control->getVisible(true))
- return $control->getClientID();
- }
- else
- return $id;
- }
- return '';
- }
-
- /**
- * Publish the the rating style css file and rating image files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->publishStyle($this->getRatingStyle());
- $this->_ratingImages = $this->publishImages($this->getRatingStyle());
- $this->registerClientScript();
- }
-
- /**
- * @param string rating style name
- * @return string URL of the css style file
- */
- protected function publishStyle($style)
- {
- $cs = $this->getPage()->getClientScript();
- $url = $this->getAssetUrl($style.'.css');
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- return $url;
- }
-
- /**
- * @param string rating style name
- * @param string rating image file extension, default is '.gif'
- * @return array URL of publish the rating images
- */
- protected function publishImages($style, $fileExt='.gif')
- {
- $types = array('blank', 'selected', 'half', 'combined');
- $files = array();
- foreach($types as $type)
- $files[$type] = $this->getAssetUrl("{$style}_{$type}{$fileExt}");
- return $files;
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('ratings');
- }
-
- /**
- * @param string asset file in the self::SCRIPT_PATH directory.
- * @return string asset file url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Add rating style class name to the class attribute
- * when {@link setReadOnly ReadOnly} property is true and when the
- * {@link setCssClass CssClass} property is empty.
- * @param THtmlWriter renderer
- */
- public function render($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl(
- $this->getClientClassName(), $this->getPostBackOptions());
- parent::render($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRatingList';
- }
-}
-
+<?php +/** + * TRatingList class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TRadioButtonList class + */ +Prado::using('System.Web.UI.WebControls.TRadioButtonList'); + +/** + * TRatingList class. + * + * This class is EXPERIMENTAL. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRatingList extends TRadioButtonList +{ + /** + * Script path relative to the TClientScriptManager::SCRIPT_PATH + */ + const SCRIPT_PATH='prado/ratings'; + + /** + * @var array list of published rating images. + */ + private $_ratingImages = array(); + + /** + * Sets the default repeat direction to horizontal. + */ + public function __construct() + { + parent::__construct(); + $this->setRepeatDirection(TRepeatDirection::Horizontal); + } + + /** + * @return boolean whether the items in the column can be edited. Defaults to false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the items in the column can be edited + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Wrapper for {@link setReadOnly ReadOnly} property. + * @return boolean whether the rating list can be edited. Defaults to true. + */ + public function getAllowInput() + { + return !$this->getReadOnly(); + } + + /** + * Wrapper for {@link setReadOnly ReadOnly} property. + * @param boolean whether the rating list can be edited + */ + public function setAllowInput($value) + { + $this->setReadOnly(!TPropertyValue::ensureBoolean($value)); + } + + /** + * Wrapper for {@link setReadOnly ReadOnly} property. + * @param boolean whether the rating list can be edited + */ + public function setEnabled($value) + { + $this->setReadOnly(!TPropertyValue::ensureBoolean($value)); + } + + /** + * The repeat layout must be Table. + * @param string repeat layout type + * @throws TInvaliddataValueException when repeat layout is not Table. + */ + public function setRepeatLayout($value) + { + if($value!==TRepeatLayout::Table) + throw new TInvalidDataValueException('ratinglist_table_layout_only'); + else + parent::setRepeatLayout($value); + } + + /** + * @return float rating value. + */ + public function getRating() + { + $rating = $this->getViewState('Rating', null); + if ($rating === null) + return $this->getSelectedIndex()+1; + else + return $rating; + } + + /** + * @param float rating value, also sets the selected Index + */ + public function setRating($value) + { + $value = TPropertyValue::ensureFloat($value); + $this->setViewState('Rating', $value, null); + $index = $this->getRatingIndex($value); + parent::setSelectedIndex($index); + } + + public function setSelectedIndex($value) + { + $this->setRating($value+1); + parent::setSelectedIndex($value); + } + + /** + * @param float rating value + * @return int rating as integer + */ + protected function getRatingIndex($rating) + { + $interval = $this->getHalfRatingInterval(); + $base = intval($rating)-1; + $remainder = $rating-$base-1; + return $remainder > $interval[1] ? $base+1 : $base; + } + + /** + * @param int change the rating selection index + */ + public function onSelectedIndexChanged($param) + { + $value = $this->getRating(); + $value = TPropertyValue::ensureInteger($value); + $this->setRating($value); + parent::onSelectedIndexChanged($param); + } + + /** + * @return string control or html element ID for displaying a caption. + */ + public function getCaptionID() + { + return $this->getViewState('CaptionID', ''); + } + + /** + * @param string control or html element ID for displaying a caption. + */ + public function setCaptionID($value) + { + $this->setViewState('CaptionID', $value, ''); + } + + protected function getCaptionControl() + { + if(($id=$this->getCaptionID())!=='') + { + if($control=$this->getParent()->findControl($id)) + return $control; + } + throw new TInvalidDataValueException( + 'ratinglist_invalid_caption_id',$id,$this->getID()); + } + + /** + * @return string caption text. Default is "Rate It:". + */ + public function getCaption() + { + return $this->getCaptionControl()->getText(); + } + + /** + * @return TRatingListStyle current rating style + */ + public function setCaption($value) + { + $this->getCaptionControl()->setText($value); + } + + /** + * @param string set the rating style, default is "default" + */ + public function setRatingStyle($value) + { + $this->setViewState('RatingStyle', $value, 'default'); + } + + /** + * @return TRatingListStyle current rating style + */ + public function getRatingStyle() + { + return $this->getViewState('RatingStyle', 'default'); + } + + /** + * @return string rating style css class name. + */ + protected function getRatingStyleCssClass() + { + return 'TRatingList_'.$this->getRatingStyle(); + } + + /** + * Sets the interval such that those rating values within the interval + * will be considered as a half star rating. + * @param array rating display half value interval, default is array(0.3, 0.7); + */ + public function setHalfRatingInterval($value) + { + $this->setViewState('HalfRating', + TPropertyValue::ensureArray($value), array(0.3, 0.7)); + } + + /** + * @return array rating display half value interval, default is array(0.3, 0.7); + */ + public function getHalfRatingInterval() + { + return $this->getViewState('HalfRating', array(0.3, 0.7)); + } + + /** + * @return array list of post back options. + */ + protected function getPostBackOptions() + { + $options = parent::getPostBackOptions(); + $options['AutoPostBack'] = $this->getAutoPostBack(); + $options['ReadOnly'] = $this->getReadOnly(); + $options['Style'] = $this->getRatingStyleCssClass(); + $options['CaptionID'] = $this->getCaptionControlID(); + $options['SelectedIndex'] = $this->getSelectedIndex(); + $options['Rating'] = $this->getRating(); + $options['HalfRating'] = $this->getHalfRatingInterval(); + return $options; + } + + /** + * @return string find the client ID of the caption control. + */ + protected function getCaptionControlID() + { + if(($id=$this->getCaptionID())!=='') + { + if($control=$this->getParent()->findControl($id)) + { + if($control->getVisible(true)) + return $control->getClientID(); + } + else + return $id; + } + return ''; + } + + /** + * Publish the the rating style css file and rating image files. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->publishStyle($this->getRatingStyle()); + $this->_ratingImages = $this->publishImages($this->getRatingStyle()); + $this->registerClientScript(); + } + + /** + * @param string rating style name + * @return string URL of the css style file + */ + protected function publishStyle($style) + { + $cs = $this->getPage()->getClientScript(); + $url = $this->getAssetUrl($style.'.css'); + if(!$cs->isStyleSheetFileRegistered($url)) + $cs->registerStyleSheetFile($url, $url); + return $url; + } + + /** + * @param string rating style name + * @param string rating image file extension, default is '.gif' + * @return array URL of publish the rating images + */ + protected function publishImages($style, $fileExt='.gif') + { + $types = array('blank', 'selected', 'half', 'combined'); + $files = array(); + foreach($types as $type) + $files[$type] = $this->getAssetUrl("{$style}_{$type}{$fileExt}"); + return $files; + } + + /** + * Registers the relevant JavaScript. + */ + protected function registerClientScript() + { + $cs=$this->getPage()->getClientScript(); + $cs->registerPradoScript('ratings'); + } + + /** + * @param string asset file in the self::SCRIPT_PATH directory. + * @return string asset file url. + */ + protected function getAssetUrl($file='') + { + $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl(); + return $base.'/'.self::SCRIPT_PATH.'/'.$file; + } + + /** + * Add rating style class name to the class attribute + * when {@link setReadOnly ReadOnly} property is true and when the + * {@link setCssClass CssClass} property is empty. + * @param THtmlWriter renderer + */ + public function render($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerPostBackControl( + $this->getClientClassName(), $this->getPostBackOptions()); + parent::render($writer); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TRatingList'; + } +} + diff --git a/framework/Web/UI/WebControls/TReCaptcha.php b/framework/Web/UI/WebControls/TReCaptcha.php index b9ba0070..cbdc2e36 100644 --- a/framework/Web/UI/WebControls/TReCaptcha.php +++ b/framework/Web/UI/WebControls/TReCaptcha.php @@ -1,233 +1,233 @@ -<?php
-
-/**
- * TReCaptcha class file
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @link http://www.devworx.hu/
- * @copyright Copyright © 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
- Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
-
-/**
- * TReCaptcha class.
- *
- * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
- * to determine if the input is entered by a real user instead of some program. It can
- * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
- *
- * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
- * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
- * of the site you will need to register and get a public and a private API key pair, and
- * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey}
- * and {@link setPublicKey PublicKey} properties.
- *
- * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all
- * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
- * control on the page will lead to unpredictable results, and the user will most likely unable to solve
- * any of them successfully.
- *
- * Upon postback, user input can be validated by calling {@link validate()}.
- * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
- * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
- * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
- * input process, you must make sure that you call validate() only once, either at the end of the input process, or
- * you store the result till the end of the processing.
- *
- * The following template shows a typical use of TReCaptcha control:
- * <code>
- * <com:TReCaptcha ID="Captcha"
- * PublicKey="..."
- * PrivateKey="..."
- * />
- * <com:TReCaptchaValidator ControlToValidate="Captcha"
- * ErrorMessage="You are challenged!" />
- * </code>
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TReCaptcha extends TWebControl implements IValidatable
-{
- private $_isValid=true;
-
- const ChallengeFieldName = 'recaptcha_challenge_field';
- const ResponseFieldName = 'recaptcha_response_field';
-
- public function getTagName()
- {
- return 'span';
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- public function getValidationPropertyValue()
- {
- return $this->Request[$this->getChallengeFieldName()];
- }
-
- public function getPublicKey()
- {
- return $this->getViewState('PublicKey');
- }
-
- public function setPublicKey($value)
- {
- return $this->setViewState('PublicKey', TPropertyValue::ensureString($value));
- }
-
- public function getPrivateKey()
- {
- return $this->getViewState('PrivateKey');
- }
-
- public function setPrivateKey($value)
- {
- return $this->setViewState('PrivateKey', TPropertyValue::ensureString($value));
- }
-
- public function getThemeName()
- {
- return $this->getViewState('ThemeName');
- }
-
- public function setThemeName($value)
- {
- return $this->setViewState('ThemeName', TPropertyValue::ensureString($value));
- }
-
- public function getCustomTranslations()
- {
- return TPropertyValue::ensureArray($this->getViewState('CustomTranslations'));
- }
-
- public function setCustomTranslations($value)
- {
- return $this->setViewState('CustomTranslations', TPropertyValue::ensureArray($value));
- }
-
- public function getLanguage()
- {
- return $this->getViewState('Language');
- }
-
- public function setLanguage($value)
- {
- return $this->setViewState('Language', TPropertyValue::ensureString($value));
- }
-
- protected function getChallengeFieldName()
- {
- return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
- }
-
- public function getResponseFieldName()
- {
- return /*$this->ClientID.'_'.*/self::ResponseFieldName;
- }
-
- public function getClientSideOptions()
- {
- $options = array();
- if ($theme = $this->getThemeName())
- $options['theme'] = $theme;
- if ($lang = $this->getLanguage())
- $options['lang'] = $lang;
- if ($trans = $this->getCustomTranslations())
- $options['custom_translations'] = $trans;
- return $options;
- }
-
- public function validate()
- {
- if (!
- (
- ($challenge = @$_POST[$this->getChallengeFieldName()])
- and
- ($response = @$_POST[$this->getResponseFieldName()])
- )
- )
- return false;
-
- $resp = recaptcha_check_answer(
- $this->getPrivateKey(),
- $_SERVER["REMOTE_ADDR"],
- $challenge,
- $response
- );
- return ($resp->is_valid==1);
- }
-
- /**
- * Checks for API keys
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- if("" == $this->getPublicKey())
- throw new TConfigurationException('recaptcha_publickey_unknown');
- if("" == $this->getPrivateKey())
- throw new TConfigurationException('recaptcha_privatekey_unknown');
-
- // need to register captcha fields so they will be sent back also in callbacks
- $page = $this->getPage();
- $page->registerRequiresPostData($this->getChallengeFieldName());
- $page->registerRequiresPostData($this->getResponseFieldName());
- }
-
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- }
-
- public function regenerateToken()
- {
- // if we're in a callback, then schedule re-rendering of the control
- // if not, don't do anything, because a new challenge will be rendered anyway
- if ($this->Page->IsCallback)
- $this->Page->ClientScript->registerEndScript($this->getClientID().'::refresh','Recaptcha.reload();');
- }
-
- public function renderContents($writer)
- {
- $writer->write(TJavaScript::renderScriptBlock(
- 'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';'
- ));
-
- $html = recaptcha_get_html($this->getPublicKey());
- /*
- reCAPTCHA currently does not support multiple validations per page
- $html = str_replace(
- array(self::ChallengeFieldName,self::ResponseFieldName),
- array($this->getChallengeFieldName(),$this->getResponseFieldName()),
- $html
- );
- */
- $writer->write($html);
- }
-
-}
-
+<?php + +/** + * TReCaptcha class file + * + * @author Bérczi Gábor <gabor.berczi@devworx.hu> + * @link http://www.devworx.hu/ + * @copyright Copyright © 2011 DevWorx + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI.WebControls + */ + + Prado::using('System.3rdParty.ReCaptcha.recaptchalib'); + +/** + * TReCaptcha class. + * + * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used + * to determine if the input is entered by a real user instead of some program. It can + * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming). + * + * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically + * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services + * of the site you will need to register and get a public and a private API key pair, and + * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey} + * and {@link setPublicKey PublicKey} properties. + * + * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all + * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA + * control on the page will lead to unpredictable results, and the user will most likely unable to solve + * any of them successfully. + * + * Upon postback, user input can be validated by calling {@link validate()}. + * The {@link TReCaptchaValidator} control can also be used to do validation, which provides + * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive + * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage + * input process, you must make sure that you call validate() only once, either at the end of the input process, or + * you store the result till the end of the processing. + * + * The following template shows a typical use of TReCaptcha control: + * <code> + * <com:TReCaptcha ID="Captcha" + * PublicKey="..." + * PrivateKey="..." + * /> + * <com:TReCaptchaValidator ControlToValidate="Captcha" + * ErrorMessage="You are challenged!" /> + * </code> + * + * @author Bérczi Gábor <gabor.berczi@devworx.hu> + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TReCaptcha extends TWebControl implements IValidatable +{ + private $_isValid=true; + + const ChallengeFieldName = 'recaptcha_challenge_field'; + const ResponseFieldName = 'recaptcha_response_field'; + + public function getTagName() + { + return 'span'; + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + + public function getValidationPropertyValue() + { + return $this->Request[$this->getChallengeFieldName()]; + } + + public function getPublicKey() + { + return $this->getViewState('PublicKey'); + } + + public function setPublicKey($value) + { + return $this->setViewState('PublicKey', TPropertyValue::ensureString($value)); + } + + public function getPrivateKey() + { + return $this->getViewState('PrivateKey'); + } + + public function setPrivateKey($value) + { + return $this->setViewState('PrivateKey', TPropertyValue::ensureString($value)); + } + + public function getThemeName() + { + return $this->getViewState('ThemeName'); + } + + public function setThemeName($value) + { + return $this->setViewState('ThemeName', TPropertyValue::ensureString($value)); + } + + public function getCustomTranslations() + { + return TPropertyValue::ensureArray($this->getViewState('CustomTranslations')); + } + + public function setCustomTranslations($value) + { + return $this->setViewState('CustomTranslations', TPropertyValue::ensureArray($value)); + } + + public function getLanguage() + { + return $this->getViewState('Language'); + } + + public function setLanguage($value) + { + return $this->setViewState('Language', TPropertyValue::ensureString($value)); + } + + protected function getChallengeFieldName() + { + return /*$this->ClientID.'_'.*/self::ChallengeFieldName; + } + + public function getResponseFieldName() + { + return /*$this->ClientID.'_'.*/self::ResponseFieldName; + } + + public function getClientSideOptions() + { + $options = array(); + if ($theme = $this->getThemeName()) + $options['theme'] = $theme; + if ($lang = $this->getLanguage()) + $options['lang'] = $lang; + if ($trans = $this->getCustomTranslations()) + $options['custom_translations'] = $trans; + return $options; + } + + public function validate() + { + if (! + ( + ($challenge = @$_POST[$this->getChallengeFieldName()]) + and + ($response = @$_POST[$this->getResponseFieldName()]) + ) + ) + return false; + + $resp = recaptcha_check_answer( + $this->getPrivateKey(), + $_SERVER["REMOTE_ADDR"], + $challenge, + $response + ); + return ($resp->is_valid==1); + } + + /** + * Checks for API keys + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + + if("" == $this->getPublicKey()) + throw new TConfigurationException('recaptcha_publickey_unknown'); + if("" == $this->getPrivateKey()) + throw new TConfigurationException('recaptcha_privatekey_unknown'); + + // need to register captcha fields so they will be sent back also in callbacks + $page = $this->getPage(); + $page->registerRequiresPostData($this->getChallengeFieldName()); + $page->registerRequiresPostData($this->getResponseFieldName()); + } + + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + } + + public function regenerateToken() + { + // if we're in a callback, then schedule re-rendering of the control + // if not, don't do anything, because a new challenge will be rendered anyway + if ($this->Page->IsCallback) + $this->Page->ClientScript->registerEndScript($this->getClientID().'::refresh','Recaptcha.reload();'); + } + + public function renderContents($writer) + { + $writer->write(TJavaScript::renderScriptBlock( + 'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';' + )); + + $html = recaptcha_get_html($this->getPublicKey()); + /* + reCAPTCHA currently does not support multiple validations per page + $html = str_replace( + array(self::ChallengeFieldName,self::ResponseFieldName), + array($this->getChallengeFieldName(),$this->getResponseFieldName()), + $html + ); + */ + $writer->write($html); + } + +} + ?>
\ No newline at end of file diff --git a/framework/Web/UI/WebControls/TReCaptchaValidator.php b/framework/Web/UI/WebControls/TReCaptchaValidator.php index 7199e401..41abbc5a 100644 --- a/framework/Web/UI/WebControls/TReCaptchaValidator.php +++ b/framework/Web/UI/WebControls/TReCaptchaValidator.php @@ -1,123 +1,123 @@ -<?php
-
-/**
- * TReCaptchaValidator class file
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @link http://www.devworx.hu/
- * @copyright Copyright © 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-Prado::using('System.Web.UI.WebControls.TReCaptcha');
-
-/**
- * TReCaptchaValidator class
- *
- * TReCaptchaValidator validates user input against a reCAPTCHA represented by
- * a {@link TReCaptcha} control. The input control fails validation if its value
- * is not the same as the token displayed in reCAPTCHA. Note, if the user does
- * not enter any thing, it is still considered as failing the validation.
- *
- * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
- * to be the ID path of the {@link TReCaptcha} control.
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TReCaptchaValidator extends TBaseValidator
-{
- protected $_isvalid = null;
-
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TReCaptchaValidator';
- }
-
- public function getEnableClientScript()
- {
- return true;
- }
-
- protected function getCaptchaControl()
- {
- $control = $this->getValidationTarget();
- if (!$control)
- throw new Exception('No target control specified for TReCaptchaValidator');
- if (!($control instanceof TReCaptcha))
- throw new Exception('TReCaptchaValidator only works with TReCaptcha controls');
- return $control;
- }
-
- public function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName();
- return $options;
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input control has the same value
- * as the one displayed in the corresponding RECAPTCHA control.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- // check validity only once (if trying to evaulate multiple times, all redundant checks would fail)
- if (is_null($this->_isvalid))
- {
- $control = $this->getCaptchaControl();
- $this->_isvalid = $control->validate();
- }
- return ($this->_isvalid==true);
- }
-
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- $cs = $this->Page->getClientScript();
-
- // communicate validation status to the client side
- $value = $this->_isvalid===false ? '0' : '1';
- $cs->registerHiddenField($this->getClientID().'_1',$value);
-
- // check if we need to request a new captcha too
- if ($this->Page->IsCallback)
- {
- // force update of validator display
- if ($control = $this->getValidationTarget())
- {
- $cs->registerEndScript(
- $this->getClientID().'::validate',
- '$('.TJavaScript::quoteString($this->getClientID().'_1').').value = '.TJavaScript::quoteString($value).';'.
- 'Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).');'
- );
-
- if ($control->getVisible(true))
- if ($this->_isvalid)
- {
- // if the challenge has been solved + we're in a callback and we still reach prerender phase,
- // that means that some other validator failed and the user will be sent back to the page/form with
- // the captcha control. in this case we need to force re-rendering of the control, because once
- // solved, the old challenge won't validate anymore anyway
-
- $control->regenerateToken();
- }
- }
- }
- }
-
-}
-
+<?php + +/** + * TReCaptchaValidator class file + * + * @author Bérczi Gábor <gabor.berczi@devworx.hu> + * @link http://www.devworx.hu/ + * @copyright Copyright © 2011 DevWorx + * @license http://www.pradosoft.com/license/ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TBaseValidator'); +Prado::using('System.Web.UI.WebControls.TReCaptcha'); + +/** + * TReCaptchaValidator class + * + * TReCaptchaValidator validates user input against a reCAPTCHA represented by + * a {@link TReCaptcha} control. The input control fails validation if its value + * is not the same as the token displayed in reCAPTCHA. Note, if the user does + * not enter any thing, it is still considered as failing the validation. + * + * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate} + * to be the ID path of the {@link TReCaptcha} control. + * + * @author Bérczi Gábor <gabor.berczi@devworx.hu> + * @package System.Web.UI.WebControls + * @since 3.2 + */ +class TReCaptchaValidator extends TBaseValidator +{ + protected $_isvalid = null; + + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TReCaptchaValidator'; + } + + public function getEnableClientScript() + { + return true; + } + + protected function getCaptchaControl() + { + $control = $this->getValidationTarget(); + if (!$control) + throw new Exception('No target control specified for TReCaptchaValidator'); + if (!($control instanceof TReCaptcha)) + throw new Exception('TReCaptchaValidator only works with TReCaptcha controls'); + return $control; + } + + public function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName(); + return $options; + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input control has the same value + * as the one displayed in the corresponding RECAPTCHA control. + * + * @return boolean whether the validation succeeds + */ + protected function evaluateIsValid() + { + // check validity only once (if trying to evaulate multiple times, all redundant checks would fail) + if (is_null($this->_isvalid)) + { + $control = $this->getCaptchaControl(); + $this->_isvalid = $control->validate(); + } + return ($this->_isvalid==true); + } + + public function onPreRender($param) + { + parent::onPreRender($param); + + $cs = $this->Page->getClientScript(); + + // communicate validation status to the client side + $value = $this->_isvalid===false ? '0' : '1'; + $cs->registerHiddenField($this->getClientID().'_1',$value); + + // check if we need to request a new captcha too + if ($this->Page->IsCallback) + { + // force update of validator display + if ($control = $this->getValidationTarget()) + { + $cs->registerEndScript( + $this->getClientID().'::validate', + '$('.TJavaScript::quoteString($this->getClientID().'_1').').value = '.TJavaScript::quoteString($value).';'. + 'Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).');' + ); + + if ($control->getVisible(true)) + if ($this->_isvalid) + { + // if the challenge has been solved + we're in a callback and we still reach prerender phase, + // that means that some other validator failed and the user will be sent back to the page/form with + // the captcha control. in this case we need to force re-rendering of the control, because once + // solved, the old challenge won't validate anymore anyway + + $control->regenerateToken(); + } + } + } + } + +} + ?>
\ No newline at end of file diff --git a/framework/Web/UI/WebControls/TRegularExpressionValidator.php b/framework/Web/UI/WebControls/TRegularExpressionValidator.php index a2a5bc64..0e85907a 100644 --- a/framework/Web/UI/WebControls/TRegularExpressionValidator.php +++ b/framework/Web/UI/WebControls/TRegularExpressionValidator.php @@ -1,144 +1,144 @@ -<?php
-/**
- * TRequiredFieldValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRegularExpressionValidator class
- *
- * TRegularExpressionValidator validates whether the value of an associated
- * input component matches the pattern specified by a regular expression.
- *
- * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression}
- * property. Some commonly used regular expressions include:
- * <pre>
- * French Phone Number: (0( \d|\d ))?\d\d \d\d(\d \d| \d\d )\d\d
- * French Postal Code: \d{5}
- * German Phone Number: ((\(0\d\d\) |(\(0\d{3}\) )?\d )?\d\d \d\d \d\d|\(0\d{4}\) \d \d\d-\d\d?)
- * German Postal Code: (D-)?\d{5}
- * Email Address: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
- * Japanese Phone Number: (0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4}
- * Japanese Postal Code: \d{3}(-(\d{4}|\d{2}))?
- * P.R.C. Phone Number: (\(\d{3}\)|\d{3}-)?\d{8}
- * P.R.C. Postal Code: \d{6}
- * P.R.C. Social Security Number: \d{18}|\d{15}
- * U.S. Phone Number: ((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}
- * U.S. ZIP Code: \d{5}(-\d{4})?
- * U.S. Social Security Number: \d{3}-\d{2}-\d{4}
- * </pre>
- *
- * Note, the validation succeeds if the associated input control contains empty input.
- * Use a {@link TRequiredFieldValidator} to ensure the input is not empty.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRegularExpressionValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRegularExpressionValidator';
- }
-
- /**
- * @return string the regular expression that determines the pattern used to validate a field.
- */
- public function getRegularExpression()
- {
- return $this->getViewState('RegularExpression','');
- }
-
- /**
- * @param string the regular expression that determines the pattern used to validate a field.
- */
- public function setRegularExpression($value)
- {
- $this->setViewState('RegularExpression',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data matches the regular expression.
- * The validation always succeeds if ControlToValidate is not specified
- * or the regular expression is empty, or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
- if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='')
- {
- $mods = $this->getPatternModifiers();
- return preg_match("/^$expression\$/{$mods}",$value);
- }
- else
- return true;
- }
-
- /**
- * @param string pattern modifiers for server side validation,
- * see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
- */
- public function setPatternModifiers($value)
- {
- $this->setViewState('PatternModifiers', $value);
- }
-
- /**
- * @return string pattern modifiers, no modifiers by default.
- */
- public function getPatternModifiers()
- {
- return $this->getViewState('PatternModifiers', '');
- }
-
- /**
- * @param string pattern modifiers for clientside.
- * (Only 'g','i' and 'm' are available.)
- */
- public function setClientSidePatternModifiers($value)
- {
- $this->setViewState('ClientSidePatternModifiers', $value);
- }
-
- /**
- * @return string clientside pattern modifiers, no modifiers by default.
- */
- public function getClientSidePatternModifiers()
- {
- return $this->getViewState('ClientSidePatternModifiers', '');
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['ValidationExpression']=$this->getRegularExpression();
- $options['PatternModifiers']=$this->getClientSidePatternModifiers();
- return $options;
- }
-}
-
+<?php +/** + * TRequiredFieldValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TRegularExpressionValidator class + * + * TRegularExpressionValidator validates whether the value of an associated + * input component matches the pattern specified by a regular expression. + * + * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression} + * property. Some commonly used regular expressions include: + * <pre> + * French Phone Number: (0( \d|\d ))?\d\d \d\d(\d \d| \d\d )\d\d + * French Postal Code: \d{5} + * German Phone Number: ((\(0\d\d\) |(\(0\d{3}\) )?\d )?\d\d \d\d \d\d|\(0\d{4}\) \d \d\d-\d\d?) + * German Postal Code: (D-)?\d{5} + * Email Address: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)* + * Japanese Phone Number: (0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4} + * Japanese Postal Code: \d{3}(-(\d{4}|\d{2}))? + * P.R.C. Phone Number: (\(\d{3}\)|\d{3}-)?\d{8} + * P.R.C. Postal Code: \d{6} + * P.R.C. Social Security Number: \d{18}|\d{15} + * U.S. Phone Number: ((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4} + * U.S. ZIP Code: \d{5}(-\d{4})? + * U.S. Social Security Number: \d{3}-\d{2}-\d{4} + * </pre> + * + * Note, the validation succeeds if the associated input control contains empty input. + * Use a {@link TRequiredFieldValidator} to ensure the input is not empty. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRegularExpressionValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TRegularExpressionValidator'; + } + + /** + * @return string the regular expression that determines the pattern used to validate a field. + */ + public function getRegularExpression() + { + return $this->getViewState('RegularExpression',''); + } + + /** + * @param string the regular expression that determines the pattern used to validate a field. + */ + public function setRegularExpression($value) + { + $this->setViewState('RegularExpression',$value,''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input data matches the regular expression. + * The validation always succeeds if ControlToValidate is not specified + * or the regular expression is empty, or the input data is empty. + * @return boolean whether the validation succeeds + */ + public function evaluateIsValid() + { + if(($value=$this->getValidationValue($this->getValidationTarget()))==='') + return true; + if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='') + { + $mods = $this->getPatternModifiers(); + return preg_match("/^$expression\$/{$mods}",$value); + } + else + return true; + } + + /** + * @param string pattern modifiers for server side validation, + * see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php + */ + public function setPatternModifiers($value) + { + $this->setViewState('PatternModifiers', $value); + } + + /** + * @return string pattern modifiers, no modifiers by default. + */ + public function getPatternModifiers() + { + return $this->getViewState('PatternModifiers', ''); + } + + /** + * @param string pattern modifiers for clientside. + * (Only 'g','i' and 'm' are available.) + */ + public function setClientSidePatternModifiers($value) + { + $this->setViewState('ClientSidePatternModifiers', $value); + } + + /** + * @return string clientside pattern modifiers, no modifiers by default. + */ + public function getClientSidePatternModifiers() + { + return $this->getViewState('ClientSidePatternModifiers', ''); + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $options['ValidationExpression']=$this->getRegularExpression(); + $options['PatternModifiers']=$this->getClientSidePatternModifiers(); + return $options; + } +} + diff --git a/framework/Web/UI/WebControls/TRepeatInfo.php b/framework/Web/UI/WebControls/TRepeatInfo.php index d7c6f0b6..2604e645 100644 --- a/framework/Web/UI/WebControls/TRepeatInfo.php +++ b/framework/Web/UI/WebControls/TRepeatInfo.php @@ -1,560 +1,560 @@ -<?php
-/**
- * IRepeatInfoUser, TRepeatInfo class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * IRepeatInfoUser, TRepeatInfo class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TTable');
-
-/**
- * IRepeatInfoUser interface.
- * This interface must be implemented by classes who want to use {@link TRepeatInfo}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-interface IRepeatInfoUser
-{
- /**
- * @return boolean whether the repeat user contains footer
- */
- public function getHasFooter();
- /**
- * @return boolean whether the repeat user contains header
- */
- public function getHasHeader();
- /**
- * @return boolean whether the repeat user contains separators
- */
- public function getHasSeparators();
- /**
- * @return integer number of items to be rendered (excluding header, footer and separators)
- */
- public function getItemCount();
- /**
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the current rendering item.
- * @return TStyle CSS style used for rendering items (including header, footer and separators)
- */
- public function generateItemStyle($itemType,$index);
- /**
- * Renders an item.
- * @param THtmlWriter writer for the rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type
- * @param integer zero-based index of the item being rendered
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index);
-}
-
-/**
- * TRepeatInfo class.
- * TRepeatInfo represents repeat information for controls like {@link TCheckBoxList}.
- * The layout of the repeated items is specified via {@link setRepeatLayout RepeatLayout},
- * which can be either Table (default), Flow or Raw.
- * A table layout uses HTML table cells to organize the items while
- * a flow layout uses line breaks to organize the items.
- * The number of columns used to display the items is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- *
- * Note, the Raw layout does not contain any formatting tags and thus ignores
- * the column and repeat direction settings.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeatInfo extends TComponent
-{
- /**
- * @var string caption of the table used to organize the repeated items
- */
- private $_caption='';
- /**
- * @var TTableCaptionAlign alignment of the caption of the table used to organize the repeated items
- */
- private $_captionAlign=TTableCaptionAlign::NotSet;
- /**
- * @var integer number of columns that the items should be arranged in
- */
- private $_repeatColumns=0;
- /**
- * @var TRepeatDirection direction of the repetition
- */
- private $_repeatDirection=TRepeatDirection::Vertical;
- /**
- * @var TRepeatLayout layout of the repeated items
- */
- private $_repeatLayout=TRepeatLayout::Table;
-
- /**
- * @return string caption of the table layout
- */
- public function getCaption()
- {
- return $this->_caption;
- }
-
- /**
- * @param string caption of the table layout
- */
- public function setCaption($value)
- {
- $this->_caption=$value;
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->_captionAlign;
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout.
- */
- public function setCaptionAlign($value)
- {
- $this->_captionAlign=TPropertyValue::ensureEnum($value,'TTableCaptionAlign');
- }
-
- /**
- * @return integer the number of columns that the repeated items should be displayed in. Defaults to 0, meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->_repeatColumns;
- }
-
- /**
- * @param integer the number of columns that the repeated items should be displayed in.
- */
- public function setRepeatColumns($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('repeatinfo_repeatcolumns_invalid');
- $this->_repeatColumns=$value;
- }
-
- /**
- * @return TRepeatDirection the direction of traversing the repeated items, defaults to TRepeatDirection::Vertical
- */
- public function getRepeatDirection()
- {
- return $this->_repeatDirection;
- }
-
- /**
- * @param TRepeatDirection the direction of traversing the repeated items
- */
- public function setRepeatDirection($value)
- {
- $this->_repeatDirection=TPropertyValue::ensureEnum($value,'TRepeatDirection');
- }
-
- /**
- * @return TRepeatLayout how the repeated items should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
- */
- public function getRepeatLayout()
- {
- return $this->_repeatLayout;
- }
-
- /**
- * @param TRepeatLayout how the repeated items should be displayed, using table or using line breaks.
- */
- public function setRepeatLayout($value)
- {
- $this->_repeatLayout=TPropertyValue::ensureEnum($value,'TRepeatLayout');
- }
-
- /**
- * Renders the repeated items.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- public function renderRepeater($writer, IRepeatInfoUser $user)
- {
- if($this->_repeatLayout===TRepeatLayout::Table)
- {
- $control=new TTable;
- if($this->_caption!=='')
- {
- $control->setCaption($this->_caption);
- $control->setCaptionAlign($this->_captionAlign);
- }
- }
- else if($this->_repeatLayout===TRepeatLayout::Raw)
- {
- $this->renderRawContents($writer,$user);
- return;
- }
- else
- $control=new TWebControl;
- $control->setID($user->getClientID());
- $control->copyBaseAttributes($user);
- if($user->getHasStyle())
- $control->getStyle()->copyFrom($user->getStyle());
- $control->renderBeginTag($writer);
- $writer->writeLine();
-
- if($this->_repeatDirection===TRepeatDirection::Vertical)
- $this->renderVerticalContents($writer,$user);
- else
- $this->renderHorizontalContents($writer,$user);
-
- $control->renderEndTag($writer);
- }
-
- /**
- * Renders contents in raw format.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderRawContents($writer,$user)
- {
- if($user->getHasHeader())
- $user->renderItem($writer,$this,'Header',-1);
-
- // render items
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- for($i=0;$i<$itemCount;++$i)
- {
- $user->renderItem($writer,$this,'Item',$i);
- if($hasSeparators && $i!=$itemCount-1)
- $user->renderItem($writer,$this,'Separator',$i);
- }
- if($user->getHasFooter())
- $user->renderItem($writer,$this,'Footer',-1);
- }
-
- /**
- * Renders contents in horizontal repeat direction.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderHorizontalContents($writer,$user)
- {
- $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- $columns=$this->_repeatColumns===0?$itemCount:$this->_repeatColumns;
- $totalColumns=$hasSeparators?$columns+$columns:$columns;
- $needBreak=$columns<$itemCount;
-
- if($user->getHasHeader())
- $this->renderHeader($writer,$user,$tableLayout,$totalColumns,$needBreak);
-
- // render items
- if($tableLayout)
- {
- $writer->renderBeginTag('tbody');
- $column=0;
- for($i=0;$i<$itemCount;++$i)
- {
- if($column==0)
- $writer->renderBeginTag('tr');
- if(($style=$user->generateItemStyle('Item',$i))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Item',$i);
- $writer->renderEndTag();
- $writer->writeLine();
- if($hasSeparators && $i!=$itemCount-1)
- {
- if(($style=$user->generateItemStyle('Separator',$i))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Separator',$i);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- $column++;
- if($i==$itemCount-1)
- {
- $restColumns=$columns-$column;
- if($hasSeparators)
- $restColumns=$restColumns?$restColumns+$restColumns+1:1;
- for($j=0;$j<$restColumns;++$j)
- $writer->write("<td></td>\n");
- }
- if($column==$columns || $i==$itemCount-1)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $column=0;
- }
- }
- $writer->renderEndTag();
- }
- else
- {
- $column=0;
- for($i=0;$i<$itemCount;++$i)
- {
- $user->renderItem($writer,$this,'Item',$i);
- if($hasSeparators && $i!=$itemCount-1)
- $user->renderItem($writer,$this,'Separator',$i);
- $column++;
- if($column==$columns || $i==$itemCount-1)
- {
- if($needBreak)
- $writer->writeBreak();
- $column=0;
- }
- $writer->writeLine();
- }
- }
-
- if($user->getHasFooter())
- $this->renderFooter($writer,$user,$tableLayout,$totalColumns,$needBreak);
- }
-
- /**
- * Renders contents in veritcal repeat direction.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderVerticalContents($writer,$user)
- {
- $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- if($this->_repeatColumns<=1)
- {
- $rows=$itemCount;
- $columns=1;
- $lastColumns=1;
- }
- else
- {
- $columns=$this->_repeatColumns;
- $rows=(int)(($itemCount+$columns-1)/$columns);
- if($rows==0 && $itemCount>0)
- $rows=1;
- if(($lastColumns=$itemCount%$columns)==0)
- $lastColumns=$columns;
- }
- $totalColumns=$hasSeparators?$columns+$columns:$columns;
-
- if($user->getHasHeader())
- $this->renderHeader($writer,$user,$tableLayout,$totalColumns,false);
-
- if($tableLayout)
- {
- $writer->renderBeginTag('tbody');
- $renderedItems=0;
- for($row=0;$row<$rows;++$row)
- {
- $index=$row;
- $writer->renderBeginTag('tr');
- for($col=0;$col<$columns;++$col)
- {
- if($renderedItems>=$itemCount)
- break;
- if($col>0)
- {
- $index+=$rows;
- if($col-1>=$lastColumns)
- $index--;
- }
- if($index>=$itemCount)
- continue;
- $renderedItems++;
- if(($style=$user->generateItemStyle('Item',$index))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Item',$index);
- $writer->renderEndTag();
- $writer->writeLine();
- if(!$hasSeparators)
- continue;
- if($renderedItems<$itemCount-1)
- {
- if($columns==1)
- {
- $writer->renderEndTag();
- $writer->renderBeginTag('tr');
- }
- if(($style=$user->generateItemStyle('Separator',$index))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Separator',$index);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- else if($columns>1)
- $writer->write("<td></td>\n");
- }
- if($row==$rows-1)
- {
- $restColumns=$columns-$lastColumns;
- if($hasSeparators)
- $restColumns+=$restColumns;
- for($col=0;$col<$restColumns;++$col)
- $writer->write("<td></td>\n");
- }
- $writer->renderEndTag();
- $writer->writeLine();
- }
- $writer->renderEndTag();
- }
- else
- {
- $renderedItems=0;
- for($row=0;$row<$rows;++$row)
- {
- $index=$row;
- for($col=0;$col<$columns;++$col)
- {
- if($renderedItems>=$itemCount)
- break;
- if($col>0)
- {
- $index+=$rows;
- if($col-1>=$lastColumns)
- $index--;
- }
- if($index>=$itemCount)
- continue;
- $renderedItems++;
- $user->renderItem($writer,$this,'Item',$index);
- $writer->writeLine();
- if(!$hasSeparators)
- continue;
- if($renderedItems<$itemCount-1)
- {
- if($columns==1)
- $writer->writeBreak();
- $user->renderItem($writer,$this,'Separator',$index);
- }
- $writer->writeLine();
- }
- if($row<$rows-1 || $user->getHasFooter())
- $writer->writeBreak();
- }
- }
-
- if($user->getHasFooter())
- $this->renderFooter($writer,$user,$tableLayout,$totalColumns,false);
-
- }
-
- /**
- * Renders header.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- * @param boolean whether to render using table layout
- * @param integer number of columns to be rendered
- * @param boolean if a line break is needed at the end
- */
- protected function renderHeader($writer,$user,$tableLayout,$columns,$needBreak)
- {
- if($tableLayout)
- {
- $writer->renderBeginTag('thead');
- $writer->renderBeginTag('tr');
- if($columns>1)
- $writer->addAttribute('colspan',"$columns");
- $writer->addAttribute('scope','col');
- if(($style=$user->generateItemStyle('Header',-1))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('th');
- $user->renderItem($writer,$this,'Header',-1);
- $writer->renderEndTag();
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
- else
- {
- $user->renderItem($writer,$this,'Header',-1);
- if($needBreak)
- $writer->writeBreak();
- }
- $writer->writeLine();
- }
-
- /**
- * Renders footer.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- * @param boolean whether to render using table layout
- * @param integer number of columns to be rendered
- */
- protected function renderFooter($writer,$user,$tableLayout,$columns)
- {
- if($tableLayout)
- {
- $writer->renderBeginTag('tfoot');
- $writer->renderBeginTag('tr');
- if($columns>1)
- $writer->addAttribute('colspan',"$columns");
- if(($style=$user->generateItemStyle('Footer',-1))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Footer',-1);
- $writer->renderEndTag();
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
- else
- $user->renderItem($writer,$this,'Footer',-1);
- $writer->writeLine();
- }
-}
-
-
-/**
- * TRepeatDirection class.
- * TRepeatDirection defines the enumerable type for the possible directions
- * that repeated contents can repeat along
- *
- * The following enumerable values are defined:
- * - Vertical
- * - Horizontal
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRepeatDirection extends TEnumerable
-{
- const Vertical='Vertical';
- const Horizontal='Horizontal';
-}
-
-/**
- * TRepeatLayout class.
- * TRepeatLayout defines the enumerable type for the possible layouts
- * that repeated contents can take.
- *
- * The following enumerable values are defined:
- * - Table: the repeated contents are organized using an HTML table
- * - Flow: the repeated contents are organized using HTML spans and breaks
- * - Raw: the repeated contents are stacked together without any additional decorations
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRepeatLayout extends TEnumerable
-{
- const Table='Table';
- const Flow='Flow';
- const Raw='Raw';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TTable'); + +/** + * IRepeatInfoUser interface. + * This interface must be implemented by classes who want to use {@link TRepeatInfo}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +interface IRepeatInfoUser +{ + /** + * @return boolean whether the repeat user contains footer + */ + public function getHasFooter(); + /** + * @return boolean whether the repeat user contains header + */ + public function getHasHeader(); + /** + * @return boolean whether the repeat user contains separators + */ + public function getHasSeparators(); + /** + * @return integer number of items to be rendered (excluding header, footer and separators) + */ + public function getItemCount(); + /** + * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager) + * @param integer zero-based index of the current rendering item. + * @return TStyle CSS style used for rendering items (including header, footer and separators) + */ + public function generateItemStyle($itemType,$index); + /** + * Renders an item. + * @param THtmlWriter writer for the rendering purpose + * @param TRepeatInfo repeat information + * @param string item type + * @param integer zero-based index of the item being rendered + */ + public function renderItem($writer,$repeatInfo,$itemType,$index); +} + +/** + * TRepeatInfo class. + * TRepeatInfo represents repeat information for controls like {@link TCheckBoxList}. + * The layout of the repeated items is specified via {@link setRepeatLayout RepeatLayout}, + * which can be either Table (default), Flow or Raw. + * A table layout uses HTML table cells to organize the items while + * a flow layout uses line breaks to organize the items. + * The number of columns used to display the items is specified via + * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection} + * governs the order of the items being rendered. + * + * Note, the Raw layout does not contain any formatting tags and thus ignores + * the column and repeat direction settings. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeatInfo extends TComponent +{ + /** + * @var string caption of the table used to organize the repeated items + */ + private $_caption=''; + /** + * @var TTableCaptionAlign alignment of the caption of the table used to organize the repeated items + */ + private $_captionAlign=TTableCaptionAlign::NotSet; + /** + * @var integer number of columns that the items should be arranged in + */ + private $_repeatColumns=0; + /** + * @var TRepeatDirection direction of the repetition + */ + private $_repeatDirection=TRepeatDirection::Vertical; + /** + * @var TRepeatLayout layout of the repeated items + */ + private $_repeatLayout=TRepeatLayout::Table; + + /** + * @return string caption of the table layout + */ + public function getCaption() + { + return $this->_caption; + } + + /** + * @param string caption of the table layout + */ + public function setCaption($value) + { + $this->_caption=$value; + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->_captionAlign; + } + + /** + * @return TTableCaptionAlign alignment of the caption of the table layout. + */ + public function setCaptionAlign($value) + { + $this->_captionAlign=TPropertyValue::ensureEnum($value,'TTableCaptionAlign'); + } + + /** + * @return integer the number of columns that the repeated items should be displayed in. Defaults to 0, meaning not set. + */ + public function getRepeatColumns() + { + return $this->_repeatColumns; + } + + /** + * @param integer the number of columns that the repeated items should be displayed in. + */ + public function setRepeatColumns($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('repeatinfo_repeatcolumns_invalid'); + $this->_repeatColumns=$value; + } + + /** + * @return TRepeatDirection the direction of traversing the repeated items, defaults to TRepeatDirection::Vertical + */ + public function getRepeatDirection() + { + return $this->_repeatDirection; + } + + /** + * @param TRepeatDirection the direction of traversing the repeated items + */ + public function setRepeatDirection($value) + { + $this->_repeatDirection=TPropertyValue::ensureEnum($value,'TRepeatDirection'); + } + + /** + * @return TRepeatLayout how the repeated items should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table. + */ + public function getRepeatLayout() + { + return $this->_repeatLayout; + } + + /** + * @param TRepeatLayout how the repeated items should be displayed, using table or using line breaks. + */ + public function setRepeatLayout($value) + { + $this->_repeatLayout=TPropertyValue::ensureEnum($value,'TRepeatLayout'); + } + + /** + * Renders the repeated items. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + */ + public function renderRepeater($writer, IRepeatInfoUser $user) + { + if($this->_repeatLayout===TRepeatLayout::Table) + { + $control=new TTable; + if($this->_caption!=='') + { + $control->setCaption($this->_caption); + $control->setCaptionAlign($this->_captionAlign); + } + } + else if($this->_repeatLayout===TRepeatLayout::Raw) + { + $this->renderRawContents($writer,$user); + return; + } + else + $control=new TWebControl; + $control->setID($user->getClientID()); + $control->copyBaseAttributes($user); + if($user->getHasStyle()) + $control->getStyle()->copyFrom($user->getStyle()); + $control->renderBeginTag($writer); + $writer->writeLine(); + + if($this->_repeatDirection===TRepeatDirection::Vertical) + $this->renderVerticalContents($writer,$user); + else + $this->renderHorizontalContents($writer,$user); + + $control->renderEndTag($writer); + } + + /** + * Renders contents in raw format. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + */ + protected function renderRawContents($writer,$user) + { + if($user->getHasHeader()) + $user->renderItem($writer,$this,'Header',-1); + + // render items + $hasSeparators=$user->getHasSeparators(); + $itemCount=$user->getItemCount(); + for($i=0;$i<$itemCount;++$i) + { + $user->renderItem($writer,$this,'Item',$i); + if($hasSeparators && $i!=$itemCount-1) + $user->renderItem($writer,$this,'Separator',$i); + } + if($user->getHasFooter()) + $user->renderItem($writer,$this,'Footer',-1); + } + + /** + * Renders contents in horizontal repeat direction. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + */ + protected function renderHorizontalContents($writer,$user) + { + $tableLayout=($this->_repeatLayout===TRepeatLayout::Table); + $hasSeparators=$user->getHasSeparators(); + $itemCount=$user->getItemCount(); + $columns=$this->_repeatColumns===0?$itemCount:$this->_repeatColumns; + $totalColumns=$hasSeparators?$columns+$columns:$columns; + $needBreak=$columns<$itemCount; + + if($user->getHasHeader()) + $this->renderHeader($writer,$user,$tableLayout,$totalColumns,$needBreak); + + // render items + if($tableLayout) + { + $writer->renderBeginTag('tbody'); + $column=0; + for($i=0;$i<$itemCount;++$i) + { + if($column==0) + $writer->renderBeginTag('tr'); + if(($style=$user->generateItemStyle('Item',$i))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('td'); + $user->renderItem($writer,$this,'Item',$i); + $writer->renderEndTag(); + $writer->writeLine(); + if($hasSeparators && $i!=$itemCount-1) + { + if(($style=$user->generateItemStyle('Separator',$i))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('td'); + $user->renderItem($writer,$this,'Separator',$i); + $writer->renderEndTag(); + $writer->writeLine(); + } + $column++; + if($i==$itemCount-1) + { + $restColumns=$columns-$column; + if($hasSeparators) + $restColumns=$restColumns?$restColumns+$restColumns+1:1; + for($j=0;$j<$restColumns;++$j) + $writer->write("<td></td>\n"); + } + if($column==$columns || $i==$itemCount-1) + { + $writer->renderEndTag(); + $writer->writeLine(); + $column=0; + } + } + $writer->renderEndTag(); + } + else + { + $column=0; + for($i=0;$i<$itemCount;++$i) + { + $user->renderItem($writer,$this,'Item',$i); + if($hasSeparators && $i!=$itemCount-1) + $user->renderItem($writer,$this,'Separator',$i); + $column++; + if($column==$columns || $i==$itemCount-1) + { + if($needBreak) + $writer->writeBreak(); + $column=0; + } + $writer->writeLine(); + } + } + + if($user->getHasFooter()) + $this->renderFooter($writer,$user,$tableLayout,$totalColumns,$needBreak); + } + + /** + * Renders contents in veritcal repeat direction. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + */ + protected function renderVerticalContents($writer,$user) + { + $tableLayout=($this->_repeatLayout===TRepeatLayout::Table); + $hasSeparators=$user->getHasSeparators(); + $itemCount=$user->getItemCount(); + if($this->_repeatColumns<=1) + { + $rows=$itemCount; + $columns=1; + $lastColumns=1; + } + else + { + $columns=$this->_repeatColumns; + $rows=(int)(($itemCount+$columns-1)/$columns); + if($rows==0 && $itemCount>0) + $rows=1; + if(($lastColumns=$itemCount%$columns)==0) + $lastColumns=$columns; + } + $totalColumns=$hasSeparators?$columns+$columns:$columns; + + if($user->getHasHeader()) + $this->renderHeader($writer,$user,$tableLayout,$totalColumns,false); + + if($tableLayout) + { + $writer->renderBeginTag('tbody'); + $renderedItems=0; + for($row=0;$row<$rows;++$row) + { + $index=$row; + $writer->renderBeginTag('tr'); + for($col=0;$col<$columns;++$col) + { + if($renderedItems>=$itemCount) + break; + if($col>0) + { + $index+=$rows; + if($col-1>=$lastColumns) + $index--; + } + if($index>=$itemCount) + continue; + $renderedItems++; + if(($style=$user->generateItemStyle('Item',$index))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('td'); + $user->renderItem($writer,$this,'Item',$index); + $writer->renderEndTag(); + $writer->writeLine(); + if(!$hasSeparators) + continue; + if($renderedItems<$itemCount-1) + { + if($columns==1) + { + $writer->renderEndTag(); + $writer->renderBeginTag('tr'); + } + if(($style=$user->generateItemStyle('Separator',$index))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('td'); + $user->renderItem($writer,$this,'Separator',$index); + $writer->renderEndTag(); + $writer->writeLine(); + } + else if($columns>1) + $writer->write("<td></td>\n"); + } + if($row==$rows-1) + { + $restColumns=$columns-$lastColumns; + if($hasSeparators) + $restColumns+=$restColumns; + for($col=0;$col<$restColumns;++$col) + $writer->write("<td></td>\n"); + } + $writer->renderEndTag(); + $writer->writeLine(); + } + $writer->renderEndTag(); + } + else + { + $renderedItems=0; + for($row=0;$row<$rows;++$row) + { + $index=$row; + for($col=0;$col<$columns;++$col) + { + if($renderedItems>=$itemCount) + break; + if($col>0) + { + $index+=$rows; + if($col-1>=$lastColumns) + $index--; + } + if($index>=$itemCount) + continue; + $renderedItems++; + $user->renderItem($writer,$this,'Item',$index); + $writer->writeLine(); + if(!$hasSeparators) + continue; + if($renderedItems<$itemCount-1) + { + if($columns==1) + $writer->writeBreak(); + $user->renderItem($writer,$this,'Separator',$index); + } + $writer->writeLine(); + } + if($row<$rows-1 || $user->getHasFooter()) + $writer->writeBreak(); + } + } + + if($user->getHasFooter()) + $this->renderFooter($writer,$user,$tableLayout,$totalColumns,false); + + } + + /** + * Renders header. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + * @param boolean whether to render using table layout + * @param integer number of columns to be rendered + * @param boolean if a line break is needed at the end + */ + protected function renderHeader($writer,$user,$tableLayout,$columns,$needBreak) + { + if($tableLayout) + { + $writer->renderBeginTag('thead'); + $writer->renderBeginTag('tr'); + if($columns>1) + $writer->addAttribute('colspan',"$columns"); + $writer->addAttribute('scope','col'); + if(($style=$user->generateItemStyle('Header',-1))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('th'); + $user->renderItem($writer,$this,'Header',-1); + $writer->renderEndTag(); + $writer->renderEndTag(); + $writer->renderEndTag(); + } + else + { + $user->renderItem($writer,$this,'Header',-1); + if($needBreak) + $writer->writeBreak(); + } + $writer->writeLine(); + } + + /** + * Renders footer. + * @param THtmlWriter writer for the rendering purpose + * @param IRepeatInfoUser repeat information user + * @param boolean whether to render using table layout + * @param integer number of columns to be rendered + */ + protected function renderFooter($writer,$user,$tableLayout,$columns) + { + if($tableLayout) + { + $writer->renderBeginTag('tfoot'); + $writer->renderBeginTag('tr'); + if($columns>1) + $writer->addAttribute('colspan',"$columns"); + if(($style=$user->generateItemStyle('Footer',-1))!==null) + $style->addAttributesToRender($writer); + $writer->renderBeginTag('td'); + $user->renderItem($writer,$this,'Footer',-1); + $writer->renderEndTag(); + $writer->renderEndTag(); + $writer->renderEndTag(); + } + else + $user->renderItem($writer,$this,'Footer',-1); + $writer->writeLine(); + } +} + + +/** + * TRepeatDirection class. + * TRepeatDirection defines the enumerable type for the possible directions + * that repeated contents can repeat along + * + * The following enumerable values are defined: + * - Vertical + * - Horizontal + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TRepeatDirection extends TEnumerable +{ + const Vertical='Vertical'; + const Horizontal='Horizontal'; +} + +/** + * TRepeatLayout class. + * TRepeatLayout defines the enumerable type for the possible layouts + * that repeated contents can take. + * + * The following enumerable values are defined: + * - Table: the repeated contents are organized using an HTML table + * - Flow: the repeated contents are organized using HTML spans and breaks + * - Raw: the repeated contents are stacked together without any additional decorations + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TRepeatLayout extends TEnumerable +{ + const Table='Table'; + const Flow='Flow'; + const Raw='Raw'; +} + diff --git a/framework/Web/UI/WebControls/TRepeater.php b/framework/Web/UI/WebControls/TRepeater.php index 6a59cbab..944b3a17 100644 --- a/framework/Web/UI/WebControls/TRepeater.php +++ b/framework/Web/UI/WebControls/TRepeater.php @@ -1,1025 +1,1025 @@ -<?php
-/**
- * TRepeater class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TRepeater class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TDataBoundControl and TDataFieldAccessor cass
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TRepeater class.
- *
- * TRepeater displays its content repeatedly based on the data fetched from
- * {@link setDataSource DataSource}.
- * The repeated contents in TRepeater are called items, which are controls and
- * can be accessed through {@link getItems Items}. When {@link dataBind()} is invoked,
- * TRepeater creates an item for each row of data and binds the data row to the item.
- * Optionally, a repeater can have a header, a footer and/or separators between items.
- *
- * The layout of the repeated contents are specified by inline templates.
- * Repeater items, header, footer, etc. are being instantiated with the corresponding
- * templates when data is being bound to the repeater.
- *
- * Since v3.1.0, the layout can also be specified by renderers. A renderer is a control class
- * that can be instantiated as repeater items, header, etc. A renderer can thus be viewed
- * as an external template (in fact, it can also be non-templated controls).
- *
- * A renderer can be any control class.
- * - If the class implements {@link IDataRenderer}, the <b>Data</b>
- * property will be set as the data row during databinding. Many PRADO controls
- * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
- * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
- * as the zero-based index of the item in the repeater item collection, and
- * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
- * {@link TRepeaterItemRenderer} may be used as the convenient base class which
- * already implements {@link IDataItemRenderer}.
- *
- * The following properties are used to specify different types of template and renderer
- * for a repeater:
- * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
- * for each repeated row of data
- * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
- * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
- * will be used instead.
- * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
- * for the repeater header.
- * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
- * for the repeater footer.
- * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
- * for content to be displayed between items.
- * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
- * used when data bound to the repeater is empty.
- *
- * If a content type is defined with both a template and a renderer, the latter takes precedence.
- *
- * When {@link dataBind()} is being called, TRepeater undergoes the following lifecycles for each row of data:
- * - create item based on templates or renderers
- * - set the row of data to the item
- * - raise {@link onItemCreated OnItemCreated}:
- * - add the item as a child control
- * - call dataBind() of the item
- * - raise {@link onItemDataBound OnItemDataBound}:
- *
- * TRepeater raises an {@link onItemCommand OnItemCommand} whenever a button control
- * within some repeater item raises a <b>OnCommand</b> event. Therefore,
- * you can handle all sorts of <b>OnCommand</b> event in a central place by
- * writing an event handler for {@link onItemCommand OnItemCommand}.
- *
- * When a page containing a repeater is post back, the repeater will restore automatically
- * all its contents, including items, header, footer and separators.
- * However, the data row associated with each item will not be recovered and become null.
- * To access the data, use one of the following ways:
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified repeater item and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
- * Be aware though, if the size of your dataset is big, your page size will become big. Some
- * complex data may also have serializing problem if saved in viewstate.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeater extends TDataBoundControl implements INamingContainer
-{
- /**
- * Repeater item types
- * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
- */
- const IT_HEADER='Header';
- const IT_FOOTER='Footer';
- const IT_ITEM='Item';
- const IT_SEPARATOR='Separator';
- const IT_ALTERNATINGITEM='AlternatingItem';
-
- /**
- * @var ITemplate template for repeater items
- */
- private $_itemTemplate=null;
- /**
- * @var ITemplate template for each alternating item
- */
- private $_alternatingItemTemplate=null;
- /**
- * @var ITemplate template for header
- */
- private $_headerTemplate=null;
- /**
- * @var ITemplate template for footer
- */
- private $_footerTemplate=null;
- /**
- * @var ITemplate template used for repeater when no data is bound
- */
- private $_emptyTemplate=null;
- /**
- * @var ITemplate template for separator
- */
- private $_separatorTemplate=null;
- /**
- * @var TRepeaterItemCollection list of repeater items
- */
- private $_items=null;
- /**
- * @var TControl header item
- */
- private $_header=null;
- /**
- * @var TControl footer item
- */
- private $_footer=null;
-
-
- /**
- * @return string the class name for repeater items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater items.
- * This property takes precedence over {@link getItemTemplate ItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setItemTemplate
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for alternative repeater items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getAlternatingItemRenderer()
- {
- return $this->getViewState('AlternatingItemRenderer','');
- }
-
- /**
- * Sets the alternative item renderer class.
- *
- * If not empty, the class will be used to instantiate as alternative repeater items.
- * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setAlternatingItemTemplate
- * @since 3.1.0
- */
- public function setAlternatingItemRenderer($value)
- {
- $this->setViewState('AlternatingItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater item separators. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSeparatorRenderer()
- {
- return $this->getViewState('SeparatorRenderer','');
- }
-
- /**
- * Sets the repeater item separator renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater item separators.
- * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSeparatorTemplate
- * @since 3.1.0
- */
- public function setSeparatorRenderer($value)
- {
- $this->setViewState('SeparatorRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater header item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the repeater header renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater header item.
- * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setHeaderTemplate
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater footer item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the repeater footer renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater footer item.
- * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setFooterTemplate
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @return string the class name for empty repeater item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEmptyRenderer()
- {
- return $this->getViewState('EmptyRenderer','');
- }
-
- /**
- * Sets the repeater empty renderer class.
- *
- * The empty renderer is created as the child of the repeater
- * if data bound to the repeater is empty.
- * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEmptyTemplate
- * @since 3.1.0
- */
- public function setEmptyRenderer($value)
- {
- $this->setViewState('EmptyRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the template for repeater items
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the template for repeater items
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','ItemTemplate');
- }
-
- /**
- * @return ITemplate the alternative template string for the item
- */
- public function getAlternatingItemTemplate()
- {
- return $this->_alternatingItemTemplate;
- }
-
- /**
- * @param ITemplate the alternative item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setAlternatingItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_alternatingItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','AlternatingItemTemplate');
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','HeaderTemplate');
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','FooterTemplate');
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the repeater
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the repeater
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','EmptyTemplate');
- }
-
- /**
- * @return ITemplate the separator template
- */
- public function getSeparatorTemplate()
- {
- return $this->_separatorTemplate;
- }
-
- /**
- * @param ITemplate the separator template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSeparatorTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_separatorTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','SeparatorTemplate');
- }
-
- /**
- * @return TControl the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TControl the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return TRepeaterItemCollection list of repeater item controls
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TRepeaterItemCollection;
- return $this->_items;
- }
-
- /**
- * @return string the field of the data source that provides the keys of the list items.
- */
- public function getDataKeyField()
- {
- return $this->getViewState('DataKeyField','');
- }
-
- /**
- * @param string the field of the data source that provides the keys of the list items.
- */
- public function setDataKeyField($value)
- {
- $this->setViewState('DataKeyField',$value,'');
- }
-
- /**
- * @return TList the keys used in the data listing control.
- */
- public function getDataKeys()
- {
- if(($dataKeys=$this->getViewState('DataKeys',null))===null)
- {
- $dataKeys=new TList;
- $this->setViewState('DataKeys',$dataKeys,null);
- }
- return $dataKeys;
- }
-
- /**
- * Creates a repeater item.
- * This method invokes {@link createItem} to create a new repeater item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @return TControl the created item, null if item is not created
- */
- private function createItemInternal($itemIndex,$itemType)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TRepeaterItemEventParameter($item);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a repeater item and performs databinding.
- * This method invokes {@link createItem} to create a new repeater item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @param mixed data to be associated with the item
- * @return TControl the created item, null if item is not created
- */
- private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TRepeaterItemEventParameter($item);
- if($item instanceof IDataRenderer)
- $item->setData($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a repeater item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TControl created repeater item
- */
- protected function createItem($itemIndex,$itemType)
- {
- $template=null;
- $classPath=null;
- switch($itemType)
- {
- case TListItemType::Item :
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- break;
- case TListItemType::AlternatingItem :
- if(($classPath=$this->getAlternatingItemRenderer())==='' && ($template=$this->_alternatingItemTemplate)===null)
- {
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- }
- break;
- case TListItemType::Header :
- $classPath=$this->getHeaderRenderer();
- $template=$this->_headerTemplate;
- break;
- case TListItemType::Footer :
- $classPath=$this->getFooterRenderer();
- $template=$this->_footerTemplate;
- break;
- case TListItemType::Separator :
- $classPath=$this->getSeparatorRenderer();
- $template=$this->_separatorTemplate;
- break;
- default:
- throw new TInvalidDataValueException('repeater_itemtype_unknown',$itemType);
- }
- if($classPath!=='')
- {
- $item=Prado::createComponent($classPath);
- if($item instanceof IItemDataRenderer)
- {
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- }
- }
- else if($template!==null)
- {
- $item=new TRepeaterItem;
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- $template->instantiateIn($item);
- }
- else
- $item=null;
-
- return $item;
- }
-
- /**
- * Creates empty repeater content.
- */
- protected function createEmptyContent()
- {
- if(($classPath=$this->getEmptyRenderer())!=='')
- $this->getControls()->add(Prado::createComponent($classPath));
- else if($this->_emptyTemplate!==null)
- $this->_emptyTemplate->instantiateIn($this);
- }
-
- /**
- * Renders the repeater.
- * This method overrides the parent implementation by rendering the body
- * content as the whole presentation of the repeater. Outer tag is not rendered.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if($this->_items && $this->_items->getCount() || $this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
- $this->renderContents($writer);
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getIsDataBound())
- $this->restoreItemsFromViewState();
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Clears up all items in the repeater.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- }
-
- /**
- * Creates repeater items based on viewstate information.
- */
- protected function restoreItemsFromViewState()
- {
- $this->reset();
- if(($itemCount=$this->getViewState('ItemCount',0))>0)
- {
- $items=$this->getItems();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $this->_header=$this->createItemInternal(-1,TListItemType::Header);
- for($i=0;$i<$itemCount;++$i)
- {
- if($hasSeparator && $i>0)
- $this->createItemInternal($i-1,TListItemType::Separator);
- $itemType=$i%2==0?TListItemType::Item : TListItemType::AlternatingItem;
- $items->add($this->createItemInternal($i,$itemType,false,null));
- }
- $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
- }
- else
- $this->createEmptyContent();
- $this->clearChildState();
- }
-
- /**
- * Performs databinding to populate repeater items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
-
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
-
- $items=$this->getItems();
- $itemIndex=0;
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- foreach($data as $key=>$dataItem)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($dataItem,$keyField));
- else
- $keys->add($key);
- if($itemIndex===0)
- $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
- if($hasSeparator && $itemIndex>0)
- $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
- $itemType=$itemIndex%2==0?TListItemType::Item : TListItemType::AlternatingItem;
- $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
- $itemIndex++;
- }
- if($itemIndex>0)
- $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
- else
- {
- $this->createEmptyContent();
- $this->dataBindChildren();
- }
- $this->setViewState('ItemCount',$itemIndex,0);
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * repeater items and their child controls.
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TRepeaterCommandEventParameter)
- {
- $this->onItemCommand($param);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked after a repeater item is created and instantiated with
- * template, but before added to the page hierarchy.
- * The repeater item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TRepeaterItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked right after an item is data bound.
- * The repeater item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TRepeaterItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked after a button control in
- * a template raises <b>OnCommand</b> event.
- * The repeater control responsible for the event
- * can be determined from the event parameter.
- * The event parameter also contains the information about
- * the initial sender of the <b>OnCommand</b> event, command name
- * and command parameter.
- * You may override this method to provide customized event handling.
- * Be sure to call parent's implementation so that
- * event handlers have chance to respond to the event.
- * @param TRepeaterCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Returns the value of the data at the specified field.
- * If data is an array, TMap or TList, the value will be returned at the index
- * of the specified field. If the data is a component with a property named
- * as the field name, the property value will be returned.
- * Otherwise, an exception will be raised.
- * @param mixed data item
- * @param mixed field name
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data is invalid
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-}
-
-/**
- * TRepeaterItemEventParameter class
- *
- * TRepeaterItemEventParameter encapsulates the parameter data for
- * {@link TRepeater::onItemCreated ItemCreated} event of {@link TRepeater} controls.
- * The {@link getItem Item} property indicates the repeater item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItemEventParameter extends TEventParameter
-{
- /**
- * The repeater item control responsible for the event.
- * @var TControl
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TControl repeater item related with the corresponding event
- */
- public function __construct($item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TControl repeater item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TRepeaterCommandEventParameter class
- *
- * TRepeaterCommandEventParameter encapsulates the parameter data for
- * {@link TRepeater::onItemCommand ItemCommand} event of {@link TRepeater} controls.
- *
- * The {@link getItem Item} property indicates the repeater item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TControl the repeater item control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>OnCommand</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl repeater item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TControl the repeater item control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TRepeaterItem class
- *
- * A TRepeaterItem control represents an item in the {@link TRepeater} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItem extends TControl implements INamingContainer, IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of repeater
- */
- private $_itemIndex;
- /**
- * type of the TRepeaterItem
- * @var TListItemType
- */
- private $_itemType;
- /**
- * data associated with this item
- * @var mixed
- */
- private $_data;
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-
-/**
- * TRepeaterItemCollection class.
- *
- * TRepeaterItemCollection represents a collection of repeater items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only objects that are descendant of {@link TControl}.
- * @param integer the speicified position.
- * @param TControl new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a control.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('repeateritemcollection_item_invalid');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TDataBoundControl and TDataFieldAccessor cass + */ +Prado::using('System.Web.UI.WebControls.TDataBoundControl'); +Prado::using('System.Util.TDataFieldAccessor'); + +/** + * TRepeater class. + * + * TRepeater displays its content repeatedly based on the data fetched from + * {@link setDataSource DataSource}. + * The repeated contents in TRepeater are called items, which are controls and + * can be accessed through {@link getItems Items}. When {@link dataBind()} is invoked, + * TRepeater creates an item for each row of data and binds the data row to the item. + * Optionally, a repeater can have a header, a footer and/or separators between items. + * + * The layout of the repeated contents are specified by inline templates. + * Repeater items, header, footer, etc. are being instantiated with the corresponding + * templates when data is being bound to the repeater. + * + * Since v3.1.0, the layout can also be specified by renderers. A renderer is a control class + * that can be instantiated as repeater items, header, etc. A renderer can thus be viewed + * as an external template (in fact, it can also be non-templated controls). + * + * A renderer can be any control class. + * - If the class implements {@link IDataRenderer}, the <b>Data</b> + * property will be set as the data row during databinding. Many PRADO controls + * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc. + * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set + * as the zero-based index of the item in the repeater item collection, and + * the <b>ItemType</b> property as the item's type (such as TListItemType::Item). + * {@link TRepeaterItemRenderer} may be used as the convenient base class which + * already implements {@link IDataItemRenderer}. + * + * The following properties are used to specify different types of template and renderer + * for a repeater: + * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}: + * for each repeated row of data + * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}: + * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer} + * will be used instead. + * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}: + * for the repeater header. + * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}: + * for the repeater footer. + * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}: + * for content to be displayed between items. + * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}: + * used when data bound to the repeater is empty. + * + * If a content type is defined with both a template and a renderer, the latter takes precedence. + * + * When {@link dataBind()} is being called, TRepeater undergoes the following lifecycles for each row of data: + * - create item based on templates or renderers + * - set the row of data to the item + * - raise {@link onItemCreated OnItemCreated}: + * - add the item as a child control + * - call dataBind() of the item + * - raise {@link onItemDataBound OnItemDataBound}: + * + * TRepeater raises an {@link onItemCommand OnItemCommand} whenever a button control + * within some repeater item raises a <b>OnCommand</b> event. Therefore, + * you can handle all sorts of <b>OnCommand</b> event in a central place by + * writing an event handler for {@link onItemCommand OnItemCommand}. + * + * When a page containing a repeater is post back, the repeater will restore automatically + * all its contents, including items, header, footer and separators. + * However, the data row associated with each item will not be recovered and become null. + * To access the data, use one of the following ways: + * - Use {@link getDataKeys DataKeys} to obtain the data key associated with + * the specified repeater item and use the key to fetch the corresponding data + * from some persistent storage such as DB. + * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback. + * Be aware though, if the size of your dataset is big, your page size will become big. Some + * complex data may also have serializing problem if saved in viewstate. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeater extends TDataBoundControl implements INamingContainer +{ + /** + * Repeater item types + * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead. + */ + const IT_HEADER='Header'; + const IT_FOOTER='Footer'; + const IT_ITEM='Item'; + const IT_SEPARATOR='Separator'; + const IT_ALTERNATINGITEM='AlternatingItem'; + + /** + * @var ITemplate template for repeater items + */ + private $_itemTemplate=null; + /** + * @var ITemplate template for each alternating item + */ + private $_alternatingItemTemplate=null; + /** + * @var ITemplate template for header + */ + private $_headerTemplate=null; + /** + * @var ITemplate template for footer + */ + private $_footerTemplate=null; + /** + * @var ITemplate template used for repeater when no data is bound + */ + private $_emptyTemplate=null; + /** + * @var ITemplate template for separator + */ + private $_separatorTemplate=null; + /** + * @var TRepeaterItemCollection list of repeater items + */ + private $_items=null; + /** + * @var TControl header item + */ + private $_header=null; + /** + * @var TControl footer item + */ + private $_footer=null; + + + /** + * @return string the class name for repeater items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getItemRenderer() + { + return $this->getViewState('ItemRenderer',''); + } + + /** + * Sets the item renderer class. + * + * If not empty, the class will be used to instantiate as repeater items. + * This property takes precedence over {@link getItemTemplate ItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setItemTemplate + * @since 3.1.0 + */ + public function setItemRenderer($value) + { + $this->setViewState('ItemRenderer',$value,''); + } + + /** + * @return string the class name for alternative repeater items. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getAlternatingItemRenderer() + { + return $this->getViewState('AlternatingItemRenderer',''); + } + + /** + * Sets the alternative item renderer class. + * + * If not empty, the class will be used to instantiate as alternative repeater items. + * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setAlternatingItemTemplate + * @since 3.1.0 + */ + public function setAlternatingItemRenderer($value) + { + $this->setViewState('AlternatingItemRenderer',$value,''); + } + + /** + * @return string the class name for repeater item separators. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getSeparatorRenderer() + { + return $this->getViewState('SeparatorRenderer',''); + } + + /** + * Sets the repeater item separator renderer class. + * + * If not empty, the class will be used to instantiate as repeater item separators. + * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setSeparatorTemplate + * @since 3.1.0 + */ + public function setSeparatorRenderer($value) + { + $this->setViewState('SeparatorRenderer',$value,''); + } + + /** + * @return string the class name for repeater header item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getHeaderRenderer() + { + return $this->getViewState('HeaderRenderer',''); + } + + /** + * Sets the repeater header renderer class. + * + * If not empty, the class will be used to instantiate as repeater header item. + * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setHeaderTemplate + * @since 3.1.0 + */ + public function setHeaderRenderer($value) + { + $this->setViewState('HeaderRenderer',$value,''); + } + + /** + * @return string the class name for repeater footer item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getFooterRenderer() + { + return $this->getViewState('FooterRenderer',''); + } + + /** + * Sets the repeater footer renderer class. + * + * If not empty, the class will be used to instantiate as repeater footer item. + * This property takes precedence over {@link getFooterTemplate FooterTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setFooterTemplate + * @since 3.1.0 + */ + public function setFooterRenderer($value) + { + $this->setViewState('FooterRenderer',$value,''); + } + + /** + * @return string the class name for empty repeater item. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEmptyRenderer() + { + return $this->getViewState('EmptyRenderer',''); + } + + /** + * Sets the repeater empty renderer class. + * + * The empty renderer is created as the child of the repeater + * if data bound to the repeater is empty. + * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}. + * + * @param string the renderer class name in namespace format. + * @see setEmptyTemplate + * @since 3.1.0 + */ + public function setEmptyRenderer($value) + { + $this->setViewState('EmptyRenderer',$value,''); + } + + /** + * @return ITemplate the template for repeater items + */ + public function getItemTemplate() + { + return $this->_itemTemplate; + } + + /** + * @param ITemplate the template for repeater items + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_itemTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','ItemTemplate'); + } + + /** + * @return ITemplate the alternative template string for the item + */ + public function getAlternatingItemTemplate() + { + return $this->_alternatingItemTemplate; + } + + /** + * @param ITemplate the alternative item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setAlternatingItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_alternatingItemTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','AlternatingItemTemplate'); + } + + /** + * @return ITemplate the header template + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate the header template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setHeaderTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_headerTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','HeaderTemplate'); + } + + /** + * @return ITemplate the footer template + */ + public function getFooterTemplate() + { + return $this->_footerTemplate; + } + + /** + * @param ITemplate the footer template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setFooterTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_footerTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','FooterTemplate'); + } + + /** + * @return ITemplate the template applied when no data is bound to the repeater + */ + public function getEmptyTemplate() + { + return $this->_emptyTemplate; + } + + /** + * @param ITemplate the template applied when no data is bound to the repeater + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEmptyTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_emptyTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','EmptyTemplate'); + } + + /** + * @return ITemplate the separator template + */ + public function getSeparatorTemplate() + { + return $this->_separatorTemplate; + } + + /** + * @param ITemplate the separator template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setSeparatorTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_separatorTemplate=$value; + else + throw new TInvalidDataTypeException('repeater_template_required','SeparatorTemplate'); + } + + /** + * @return TControl the header item + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return TControl the footer item + */ + public function getFooter() + { + return $this->_footer; + } + + /** + * @return TRepeaterItemCollection list of repeater item controls + */ + public function getItems() + { + if(!$this->_items) + $this->_items=new TRepeaterItemCollection; + return $this->_items; + } + + /** + * @return string the field of the data source that provides the keys of the list items. + */ + public function getDataKeyField() + { + return $this->getViewState('DataKeyField',''); + } + + /** + * @param string the field of the data source that provides the keys of the list items. + */ + public function setDataKeyField($value) + { + $this->setViewState('DataKeyField',$value,''); + } + + /** + * @return TList the keys used in the data listing control. + */ + public function getDataKeys() + { + if(($dataKeys=$this->getViewState('DataKeys',null))===null) + { + $dataKeys=new TList; + $this->setViewState('DataKeys',$dataKeys,null); + } + return $dataKeys; + } + + /** + * Creates a repeater item. + * This method invokes {@link createItem} to create a new repeater item. + * @param integer zero-based item index. + * @param TListItemType item type + * @return TControl the created item, null if item is not created + */ + private function createItemInternal($itemIndex,$itemType) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TRepeaterItemEventParameter($item); + $this->onItemCreated($param); + $this->getControls()->add($item); + return $item; + } + else + return null; + } + + /** + * Creates a repeater item and performs databinding. + * This method invokes {@link createItem} to create a new repeater item. + * @param integer zero-based item index. + * @param TListItemType item type + * @param mixed data to be associated with the item + * @return TControl the created item, null if item is not created + */ + private function createItemWithDataInternal($itemIndex,$itemType,$dataItem) + { + if(($item=$this->createItem($itemIndex,$itemType))!==null) + { + $param=new TRepeaterItemEventParameter($item); + if($item instanceof IDataRenderer) + $item->setData($dataItem); + $this->onItemCreated($param); + $this->getControls()->add($item); + $item->dataBind(); + $this->onItemDataBound($param); + return $item; + } + else + return null; + } + + /** + * Creates a repeater item instance based on the item type and index. + * @param integer zero-based item index + * @param TListItemType item type + * @return TControl created repeater item + */ + protected function createItem($itemIndex,$itemType) + { + $template=null; + $classPath=null; + switch($itemType) + { + case TListItemType::Item : + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + break; + case TListItemType::AlternatingItem : + if(($classPath=$this->getAlternatingItemRenderer())==='' && ($template=$this->_alternatingItemTemplate)===null) + { + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + } + break; + case TListItemType::Header : + $classPath=$this->getHeaderRenderer(); + $template=$this->_headerTemplate; + break; + case TListItemType::Footer : + $classPath=$this->getFooterRenderer(); + $template=$this->_footerTemplate; + break; + case TListItemType::Separator : + $classPath=$this->getSeparatorRenderer(); + $template=$this->_separatorTemplate; + break; + default: + throw new TInvalidDataValueException('repeater_itemtype_unknown',$itemType); + } + if($classPath!=='') + { + $item=Prado::createComponent($classPath); + if($item instanceof IItemDataRenderer) + { + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + } + } + else if($template!==null) + { + $item=new TRepeaterItem; + $item->setItemIndex($itemIndex); + $item->setItemType($itemType); + $template->instantiateIn($item); + } + else + $item=null; + + return $item; + } + + /** + * Creates empty repeater content. + */ + protected function createEmptyContent() + { + if(($classPath=$this->getEmptyRenderer())!=='') + $this->getControls()->add(Prado::createComponent($classPath)); + else if($this->_emptyTemplate!==null) + $this->_emptyTemplate->instantiateIn($this); + } + + /** + * Renders the repeater. + * This method overrides the parent implementation by rendering the body + * content as the whole presentation of the repeater. Outer tag is not rendered. + * @param THtmlWriter writer + */ + public function render($writer) + { + if($this->_items && $this->_items->getCount() || $this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='') + $this->renderContents($writer); + } + + /** + * Saves item count in viewstate. + * This method is invoked right before control state is to be saved. + */ + public function saveState() + { + parent::saveState(); + if($this->_items) + $this->setViewState('ItemCount',$this->_items->getCount(),0); + else + $this->clearViewState('ItemCount'); + } + + /** + * Loads item count information from viewstate. + * This method is invoked right after control state is loaded. + */ + public function loadState() + { + parent::loadState(); + if(!$this->getIsDataBound()) + $this->restoreItemsFromViewState(); + $this->clearViewState('ItemCount'); + } + + /** + * Clears up all items in the repeater. + */ + public function reset() + { + $this->getControls()->clear(); + $this->getItems()->clear(); + $this->_header=null; + $this->_footer=null; + } + + /** + * Creates repeater items based on viewstate information. + */ + protected function restoreItemsFromViewState() + { + $this->reset(); + if(($itemCount=$this->getViewState('ItemCount',0))>0) + { + $items=$this->getItems(); + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + $this->_header=$this->createItemInternal(-1,TListItemType::Header); + for($i=0;$i<$itemCount;++$i) + { + if($hasSeparator && $i>0) + $this->createItemInternal($i-1,TListItemType::Separator); + $itemType=$i%2==0?TListItemType::Item : TListItemType::AlternatingItem; + $items->add($this->createItemInternal($i,$itemType,false,null)); + } + $this->_footer=$this->createItemInternal(-1,TListItemType::Footer); + } + else + $this->createEmptyContent(); + $this->clearChildState(); + } + + /** + * Performs databinding to populate repeater items from data source. + * This method is invoked by dataBind(). + * You may override this function to provide your own way of data population. + * @param Traversable the data + */ + protected function performDataBinding($data) + { + $this->reset(); + + $keys=$this->getDataKeys(); + $keys->clear(); + $keyField=$this->getDataKeyField(); + + $items=$this->getItems(); + $itemIndex=0; + $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!==''; + foreach($data as $key=>$dataItem) + { + if($keyField!=='') + $keys->add($this->getDataFieldValue($dataItem,$keyField)); + else + $keys->add($key); + if($itemIndex===0) + $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null); + if($hasSeparator && $itemIndex>0) + $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null); + $itemType=$itemIndex%2==0?TListItemType::Item : TListItemType::AlternatingItem; + $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem)); + $itemIndex++; + } + if($itemIndex>0) + $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null); + else + { + $this->createEmptyContent(); + $this->dataBindChildren(); + } + $this->setViewState('ItemCount',$itemIndex,0); + } + + /** + * This method overrides parent's implementation to handle + * {@link onItemCommand OnItemCommand} event which is bubbled from + * repeater items and their child controls. + * This method should only be used by control developers. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TRepeaterCommandEventParameter) + { + $this->onItemCommand($param); + return true; + } + else + return false; + } + + /** + * Raises <b>OnItemCreated</b> event. + * This method is invoked after a repeater item is created and instantiated with + * template, but before added to the page hierarchy. + * The repeater item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TRepeaterItemEventParameter event parameter + */ + public function onItemCreated($param) + { + $this->raiseEvent('OnItemCreated',$this,$param); + } + + /** + * Raises <b>OnItemDataBound</b> event. + * This method is invoked right after an item is data bound. + * The repeater item control responsible for the event + * can be determined from the event parameter. + * If you override this method, be sure to call parent's implementation + * so that event handlers have chance to respond to the event. + * @param TRepeaterItemEventParameter event parameter + */ + public function onItemDataBound($param) + { + $this->raiseEvent('OnItemDataBound',$this,$param); + } + + /** + * Raises <b>OnItemCommand</b> event. + * This method is invoked after a button control in + * a template raises <b>OnCommand</b> event. + * The repeater control responsible for the event + * can be determined from the event parameter. + * The event parameter also contains the information about + * the initial sender of the <b>OnCommand</b> event, command name + * and command parameter. + * You may override this method to provide customized event handling. + * Be sure to call parent's implementation so that + * event handlers have chance to respond to the event. + * @param TRepeaterCommandEventParameter event parameter + */ + public function onItemCommand($param) + { + $this->raiseEvent('OnItemCommand',$this,$param); + } + + /** + * Returns the value of the data at the specified field. + * If data is an array, TMap or TList, the value will be returned at the index + * of the specified field. If the data is a component with a property named + * as the field name, the property value will be returned. + * Otherwise, an exception will be raised. + * @param mixed data item + * @param mixed field name + * @return mixed data value at the specified field + * @throws TInvalidDataValueException if the data is invalid + */ + protected function getDataFieldValue($data,$field) + { + return TDataFieldAccessor::getDataFieldValue($data,$field); + } +} + +/** + * TRepeaterItemEventParameter class + * + * TRepeaterItemEventParameter encapsulates the parameter data for + * {@link TRepeater::onItemCreated ItemCreated} event of {@link TRepeater} controls. + * The {@link getItem Item} property indicates the repeater item related with the event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeaterItemEventParameter extends TEventParameter +{ + /** + * The repeater item control responsible for the event. + * @var TControl + */ + private $_item=null; + + /** + * Constructor. + * @param TControl repeater item related with the corresponding event + */ + public function __construct($item) + { + $this->_item=$item; + } + + /** + * @return TControl repeater item related with the corresponding event + */ + public function getItem() + { + return $this->_item; + } +} + +/** + * TRepeaterCommandEventParameter class + * + * TRepeaterCommandEventParameter encapsulates the parameter data for + * {@link TRepeater::onItemCommand ItemCommand} event of {@link TRepeater} controls. + * + * The {@link getItem Item} property indicates the repeater item related with the event. + * The {@link getCommandSource CommandSource} refers to the control that originally + * raises the Command event. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeaterCommandEventParameter extends TCommandEventParameter +{ + /** + * @var TControl the repeater item control responsible for the event. + */ + private $_item=null; + /** + * @var TControl the control originally raises the <b>OnCommand</b> event. + */ + private $_source=null; + + /** + * Constructor. + * @param TControl repeater item responsible for the event + * @param TControl original event sender + * @param TCommandEventParameter original event parameter + */ + public function __construct($item,$source,TCommandEventParameter $param) + { + $this->_item=$item; + $this->_source=$source; + parent::__construct($param->getCommandName(),$param->getCommandParameter()); + } + + /** + * @return TControl the repeater item control responsible for the event. + */ + public function getItem() + { + return $this->_item; + } + + /** + * @return TControl the control originally raises the <b>OnCommand</b> event. + */ + public function getCommandSource() + { + return $this->_source; + } +} + +/** + * TRepeaterItem class + * + * A TRepeaterItem control represents an item in the {@link TRepeater} control, + * such as heading section, footer section, or a data item. + * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}> + * and {@link getDataItem DataItem} properties, respectively. The type of the item + * is given by {@link getItemType ItemType} property. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeaterItem extends TControl implements INamingContainer, IItemDataRenderer +{ + /** + * index of the data item in the Items collection of repeater + */ + private $_itemIndex; + /** + * type of the TRepeaterItem + * @var TListItemType + */ + private $_itemType; + /** + * data associated with this item + * @var mixed + */ + private $_data; + + /** + * @return TListItemType item type + */ + public function getItemType() + { + return $this->_itemType; + } + + /** + * @param TListItemType item type. + */ + public function setItemType($value) + { + $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType'); + } + + /** + * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection. + * If the item is not in the collection (e.g. it is a header item), it returns -1. + * @return integer zero-based index of the item. + */ + public function getItemIndex() + { + return $this->_itemIndex; + } + + /** + * Sets the zero-based index for the item. + * If the item is not in the item collection (e.g. it is a header item), -1 should be used. + * @param integer zero-based index of the item. + */ + public function setItemIndex($value) + { + $this->_itemIndex=TPropertyValue::ensureInteger($value); + } + + /** + * @return mixed data associated with the item + * @since 3.1.0 + */ + public function getData() + { + return $this->_data; + } + + /** + * @param mixed data to be associated with the item + * @since 3.1.0 + */ + public function setData($value) + { + $this->_data=$value; + } + + /** + * This property is deprecated since v3.1.0. + * @return mixed data associated with the item + * @deprecated deprecated since v3.1.0. Use {@link getData} instead. + */ + public function getDataItem() + { + return $this->getData(); + } + + /** + * This property is deprecated since v3.1.0. + * @param mixed data to be associated with the item + * @deprecated deprecated since version 3.1.0. Use {@link setData} instead. + */ + public function setDataItem($value) + { + return $this->setData($value); + } + + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + + +/** + * TRepeaterItemCollection class. + * + * TRepeaterItemCollection represents a collection of repeater items. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRepeaterItemCollection extends TList +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by inserting only objects that are descendant of {@link TControl}. + * @param integer the speicified position. + * @param TControl new item + * @throws TInvalidDataTypeException if the item to be inserted is not a control. + */ + public function insertAt($index,$item) + { + if($item instanceof TControl) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('repeateritemcollection_item_invalid'); + } +} + diff --git a/framework/Web/UI/WebControls/TRepeaterItemRenderer.php b/framework/Web/UI/WebControls/TRepeaterItemRenderer.php index 85991b38..fe5171ad 100644 --- a/framework/Web/UI/WebControls/TRepeaterItemRenderer.php +++ b/framework/Web/UI/WebControls/TRepeaterItemRenderer.php @@ -1,50 +1,50 @@ -<?php
-/**
- * TRepeaterItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TRepeaterItemRenderer class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TRepeater');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TRepeaterItemRenderer class
- *
- * TRepeaterItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TRepeater}.
- *
- * TRepeaterItemRenderer extends {@link TItemDataRenderer} and implements
- * the bubbling scheme for the OnCommand event of repeater items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TRepeaterItemRenderer extends TItemDataRenderer
-{
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TRepeater'); +Prado::using('System.Web.UI.WebControls.TItemDataRenderer'); + +/** + * TRepeaterItemRenderer class + * + * TRepeaterItemRenderer can be used as a convenient base class to + * define an item renderer class specific for {@link TRepeater}. + * + * TRepeaterItemRenderer extends {@link TItemDataRenderer} and implements + * the bubbling scheme for the OnCommand event of repeater items. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.0 + */ +class TRepeaterItemRenderer extends TItemDataRenderer +{ + /** + * This method overrides parent's implementation by wrapping event parameter + * for <b>OnCommand</b> event with item information. + * @param TControl the sender of the event + * @param TEventParameter event parameter + * @return boolean whether the event bubbling should stop here. + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param)); + return true; + } + else + return false; + } +} + diff --git a/framework/Web/UI/WebControls/TRequiredFieldValidator.php b/framework/Web/UI/WebControls/TRequiredFieldValidator.php index 97555b82..89b142bf 100644 --- a/framework/Web/UI/WebControls/TRequiredFieldValidator.php +++ b/framework/Web/UI/WebControls/TRequiredFieldValidator.php @@ -1,138 +1,138 @@ -<?php
-/**
- * TRequiredFieldValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TRequiredFieldValidator class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRequiredFieldValidator class
- *
- * TRequiredFieldValidator makes the associated input control a required field.
- * The input control fails validation if its value does not change from
- * the {@link setInitialValue InitialValue} property upon losing focus.
- *
- * Validation will also succeed if input is of TListControl type and the number
- * of selected values different from the initial value is greater than zero.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRequiredFieldValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRequiredFieldValidator';
- }
-
- /**
- * @return string the initial value of the associated input control. Defaults to empty string.
- * If the associated input control does not change from this initial value
- * upon postback, the validation fails.
- */
- public function getInitialValue()
- {
- return $this->getViewState('InitialValue','');
- }
-
- /**
- * @param string the initial value of the associated input control.
- * If the associated input control does not change from this initial value
- * upon postback, the validation fails.
- */
- public function setInitialValue($value)
- {
- $this->setViewState('InitialValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input component changes its data
- * from the {@link getInitialValue InitialValue} or the input control is not given.
- *
- * Validation will also succeed if input is of TListControl type and the
- * number of selected values different from the initial value is greater
- * than zero.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $control = $this->getValidationTarget();
- if($control instanceof TListControl)
- return $this->validateListControl($control);
- else if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
- return $this->validateRadioButtonGroup($control);
- else
- return $this->validateStandardControl($control);
- }
-
- private function validateListControl($control)
- {
- $initial = trim($this->getInitialValue());
- $count = 0;
- foreach($control->getItems() as $item)
- {
- if($item->getSelected() && $item->getValue() != $initial)
- $count++;
- }
- return $count > 0;
- }
-
- private function validateRadioButtonGroup($control)
- {
- $initial = trim($this->getInitialValue());
- foreach($control->getRadioButtonsInGroup() as $radio)
- {
- if($radio->getChecked())
- {
- if(strlen($value = $radio->getValue()) > 0)
- return $value !== $initial;
- else
- return true;
- }
- }
- return false;
- }
-
- private function validateStandardControl($control)
- {
- $initial = trim($this->getInitialValue());
- $value=$this->getValidationValue($control);
- return (is_bool($value) && $value) || trim($value)!==$initial;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['InitialValue']=$this->getInitialValue();
- $control = $this->getValidationTarget();
- if($control instanceof TListControl)
- $options['TotalItems'] = $control->getItemCount();
- if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
- $options['GroupName'] = $control->getGroupName();
- return $options;
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Using TBaseValidator class + */ +Prado::using('System.Web.UI.WebControls.TBaseValidator'); + +/** + * TRequiredFieldValidator class + * + * TRequiredFieldValidator makes the associated input control a required field. + * The input control fails validation if its value does not change from + * the {@link setInitialValue InitialValue} property upon losing focus. + * + * Validation will also succeed if input is of TListControl type and the number + * of selected values different from the initial value is greater than zero. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TRequiredFieldValidator extends TBaseValidator +{ + /** + * Gets the name of the javascript class responsible for performing validation for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TRequiredFieldValidator'; + } + + /** + * @return string the initial value of the associated input control. Defaults to empty string. + * If the associated input control does not change from this initial value + * upon postback, the validation fails. + */ + public function getInitialValue() + { + return $this->getViewState('InitialValue',''); + } + + /** + * @param string the initial value of the associated input control. + * If the associated input control does not change from this initial value + * upon postback, the validation fails. + */ + public function setInitialValue($value) + { + $this->setViewState('InitialValue',TPropertyValue::ensureString($value),''); + } + + /** + * This method overrides the parent's implementation. + * The validation succeeds if the input component changes its data + * from the {@link getInitialValue InitialValue} or the input control is not given. + * + * Validation will also succeed if input is of TListControl type and the + * number of selected values different from the initial value is greater + * than zero. + * + * @return boolean whether the validation succeeds + */ + protected function evaluateIsValid() + { + $control = $this->getValidationTarget(); + if($control instanceof TListControl) + return $this->validateListControl($control); + else if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0) + return $this->validateRadioButtonGroup($control); + else + return $this->validateStandardControl($control); + } + + private function validateListControl($control) + { + $initial = trim($this->getInitialValue()); + $count = 0; + foreach($control->getItems() as $item) + { + if($item->getSelected() && $item->getValue() != $initial) + $count++; + } + return $count > 0; + } + + private function validateRadioButtonGroup($control) + { + $initial = trim($this->getInitialValue()); + foreach($control->getRadioButtonsInGroup() as $radio) + { + if($radio->getChecked()) + { + if(strlen($value = $radio->getValue()) > 0) + return $value !== $initial; + else + return true; + } + } + return false; + } + + private function validateStandardControl($control) + { + $initial = trim($this->getInitialValue()); + $value=$this->getValidationValue($control); + return (is_bool($value) && $value) || trim($value)!==$initial; + } + + /** + * Returns an array of javascript validator options. + * @return array javascript validator options. + */ + protected function getClientScriptOptions() + { + $options = parent::getClientScriptOptions(); + $options['InitialValue']=$this->getInitialValue(); + $control = $this->getValidationTarget(); + if($control instanceof TListControl) + $options['TotalItems'] = $control->getItemCount(); + if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0) + $options['GroupName'] = $control->getGroupName(); + return $options; + } +} + diff --git a/framework/Web/UI/WebControls/TSafeHtml.php b/framework/Web/UI/WebControls/TSafeHtml.php index e88277d4..1cd0a597 100644 --- a/framework/Web/UI/WebControls/TSafeHtml.php +++ b/framework/Web/UI/WebControls/TSafeHtml.php @@ -1,85 +1,85 @@ -<?php
-/**
- * TSafeHtml class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TSafeHtml class
- *
- * TSafeHtml is a control that strips down all potentially dangerous
- * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML}
- * project. According to the SafeHTML project, it tries to safeguard
- * the following situations when the string is to be displayed to end-users,
- * - Opening tag without its closing tag
- * - closing tag without its opening tag
- * - any of these tags: base, basefont, head, html, body, applet, object,
- * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link,
- * meta, style, title, blink, xml, etc.
- * - any of these attributes: on*, data*, dynsrc
- * - javascript:/vbscript:/about: etc. protocols
- * - expression/behavior etc. in styles
- * - any other active content.
- *
- * To use TSafeHtml, simply enclose the content to be secured within
- * the body of TSafeHtml in a template.
- *
- * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property
- * to ensure the contents gets parsed correctly.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TSafeHtml extends TControl
-{
- /**
- * Sets whether to parse the contents as UTF-7. This property enables a routine
- * that repacks the content as UTF-7 before parsing it. Defaults to false.
- * @param boolean whether to parse the contents as UTF-7
- */
- public function setRepackUTF7($value)
- {
- $this->setViewState('RepackUTF7',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether to parse the contents as UTF-7. Defaults to false.
- */
- public function getRepackUTF7()
- {
- return $this->getViewState('RepackUTF7',false);
- }
-
- /**
- * Renders body content.
- * This method overrides parent implementation by removing
- * malicious javascript code from the body content
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
- parent::render($htmlWriter);
- $writer->write($this->parseSafeHtml($htmlWriter->flush()));
- }
-
- /**
- * Use SafeHTML to remove malicous javascript from the HTML content.
- * @param string HTML content
- * @return string safer HTML content
- */
- protected function parseSafeHtml($text)
- {
- $renderer = Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
- return $renderer->parse($text, $this->getRepackUTF7());
- }
-}
-
+<?php +/** + * TSafeHtml class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TSafeHtml class + * + * TSafeHtml is a control that strips down all potentially dangerous + * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML} + * project. According to the SafeHTML project, it tries to safeguard + * the following situations when the string is to be displayed to end-users, + * - Opening tag without its closing tag + * - closing tag without its opening tag + * - any of these tags: base, basefont, head, html, body, applet, object, + * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link, + * meta, style, title, blink, xml, etc. + * - any of these attributes: on*, data*, dynsrc + * - javascript:/vbscript:/about: etc. protocols + * - expression/behavior etc. in styles + * - any other active content. + * + * To use TSafeHtml, simply enclose the content to be secured within + * the body of TSafeHtml in a template. + * + * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property + * to ensure the contents gets parsed correctly. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TSafeHtml extends TControl +{ + /** + * Sets whether to parse the contents as UTF-7. This property enables a routine + * that repacks the content as UTF-7 before parsing it. Defaults to false. + * @param boolean whether to parse the contents as UTF-7 + */ + public function setRepackUTF7($value) + { + $this->setViewState('RepackUTF7',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether to parse the contents as UTF-7. Defaults to false. + */ + public function getRepackUTF7() + { + return $this->getViewState('RepackUTF7',false); + } + + /** + * Renders body content. + * This method overrides parent implementation by removing + * malicious javascript code from the body content + * @param THtmlWriter writer + */ + public function render($writer) + { + $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter()); + parent::render($htmlWriter); + $writer->write($this->parseSafeHtml($htmlWriter->flush())); + } + + /** + * Use SafeHTML to remove malicous javascript from the HTML content. + * @param string HTML content + * @return string safer HTML content + */ + protected function parseSafeHtml($text) + { + $renderer = Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser'); + return $renderer->parse($text, $this->getRepackUTF7()); + } +} + diff --git a/framework/Web/UI/WebControls/TSlider.php b/framework/Web/UI/WebControls/TSlider.php index ce080f5f..06df52b6 100644 --- a/framework/Web/UI/WebControls/TSlider.php +++ b/framework/Web/UI/WebControls/TSlider.php @@ -1,574 +1,574 @@ -<?php
-/**
- * TSlider class file.
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-
-/**
- * TSlider class
- *
- * TSlider displays a slider for numeric input purpose. A slider consists of a 'track',
- * which define the range of possible value, and a 'handle' which can slide on the track, to select
- * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction}
- * property. By default, it's horizontal.
- *
- * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties.
- * The default range is from 0 to 100.
- * The {@link SetStepSize StepSize} property can be used to define the <b>step</b> between 2 values inside the range.
- * Notice that this step will be recomputed if there is more than 200 values between the range boundaries.
- * You can also provide the allowed values by setting the {@link SetValues Values} array.
- *
- * A 'Progress Indicator' can be displayed within the track with the {@link SetProgressIndicator ProgressIndicator} property.
- *
- * The TSlider control can be easily customized using CssClasses. You can provide your own css file, using the
- * {@link SetCssUrl CssUrl} property.
- * The css class for TSlider can be set by the {@link setCssClass CssClass} property. Default value is "Slider HorizontalSlider"
- * for an horizontal slider, and "Slider VerticalSlider" for a vertical one.
- *
- * If {@link SetAutoPostBack AutoPostBack} property is true, postback is sent as soon as the value changed.
- *
- * TSlider raises the {@link onValueChanged} event when the value of the slider has changed during postback.
- *
- * You can also attach ClientSide javascript events handler to the slider :
- * - ClientSide.onSlide is called when the handle is slided on the track. You can get the current value in the <b>value</b>
- * javascript variable. You can use this event to update on client side a label with the current value
- * - ClientSide.onChange is called when the slider value has changed (at the end of a move).
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSlider extends TWebControl implements IPostBackDataHandler, IDataRenderer
-{
- const MAX_STEPS=200;
- /**
- * @var TSliderHandle handle component
- */
- private $_handle;
- /*
- * @var boolean Wether the data has changed during postback
- */
- private $_dataChanged=false;
- /**
- * @var TSliderClientScript Clients side javascripts
- */
- private $_clientScript=null;
-
- /**
- * @return TSliderDirection Direction of slider (Horizontal or Vertical). Defaults to Horizontal.
- */
- public function getDirection()
- {
- return $this->getViewState('Direction', TSliderDirection::Horizontal);
- }
-
- /**
- * @param TSliderDirection Direction of slider (Horizontal or Vertical)
- */
- public function setDirection($value)
- {
- $this->setViewState('Direction', TPropertyValue::ensureEnum($value,'TSliderDirection'),TSliderDirection::Horizontal);
- }
-
- /**
- * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to '' (a default CSS file will be applied in this case.)
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl','');
- }
-
- /**
- * @param string URL for the CSS file including all relevant CSS class definitions.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return float Maximum value for the slider. Defaults to 100.0.
- */
- public function getMaxValue()
- {
- return $this->getViewState('MaxValue',100.0);
- }
-
- /**
- * @param float Maximum value for slider
- */
- public function setMaxValue($value)
- {
- $this->setViewState('MaxValue', TPropertyValue::ensureFloat($value),100.0);
- }
-
- /**
- * @return float Minimum value for slider. Defaults to 0.0.
- */
- public function getMinValue()
- {
- return $this->getViewState('MinValue',0.0);
- }
-
- /**
- * @param float Minimum value for slider
- */
- public function setMinValue($value)
- {
- $this->setViewState('MinValue', TPropertyValue::ensureFloat($value),0.0);
- }
-
- /**
- * @return float Step size. Defaults to 1.0.
- */
- public function getStepSize()
- {
- return $this->getViewState('StepSize', 1.0);
- }
-
- /**
- * Sets the step size used to determine the places where the slider handle can stop at.
- * An evenly distributed stop marks will be generated according to
- * {@link getMinValue MinValue}, {@link getMaxValue MaxValue} and StepSize.
- * To use uneven stop marks, set {@link setValues Values}.
- * @param float Step size.
- */
- public function setStepSize($value)
- {
- $this->setViewState('StepSize', $value, 1.0);
- }
-
- /**
- * @return boolean wether to display a progress indicator or not. Defaults to true.
- */
- public function getProgressIndicator ()
- {
- return $this->getViewState('ProgressIndicator', true);
- }
-
- /**
- * @param boolean wether to display a progress indicator or not. Defaults to true.
- */
- public function setProgressIndicator ($value)
- {
- $this->setViewState('ProgressIndicator', TPropertyValue::ensureBoolean($value), true);
- }
- /**
- * @return float current value of slider
- */
- public function getValue()
- {
- return $this->getViewState('Value',0.0);
- }
-
- /**
- * @param float current value of slider
- */
- public function setValue($value)
- {
- $this->setViewState('Value', TPropertyValue::ensureFloat($value),0.0);
- }
-
- /**
- * Returns the value of the TSlider control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getValue()}.
- * @return string the value of the TSlider control.
- * @see getValue
- */
- public function getData()
- {
- return $this->getValue();
- }
-
- /**
- * Sets the value of the TSlider control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setValue()}.
- * @param string the value of the TSlider control.
- * @see setValue
- */
- public function setData($value)
- {
- $this->setValue($value);
- }
-
- /**
- * @return array list of allowed values the slider can take. Defaults to an empty array.
- */
- public function getValues()
- {
- return $this->getViewState('Values', array());
- }
-
- /**
- * Sets the possible values that the slider can take.
- * If this is set, {@link setStepSize StepSize} will be ignored. The latter
- * generates a set of evenly distributed candidate values.
- * @param array list of allowed values the slider can take
- */
- public function setValues($value)
- {
- $this->setViewState('Values', TPropertyValue::ensureArray($value), array());
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user modifies the slider value. Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * modifies the slider value.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TSlider';
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getValue Value} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onValueChanged(null);
- }
-
- /**
- * Raises <b>OnValueChanged</b> event.
- * This method is invoked when the {@link getValue Value}
- * property changes on postback.
- * If you override this method, be sure to call the parent implementation to ensure
- * the invocation of the attached event handlers.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onValueChanged($param)
- {
- $this->raiseEvent('OnValueChanged',$this,$param);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=(float)$values[$this->getClientID().'_1'];
- if($this->getValue()!==$value)
- {
- $this->setValue($value);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Gets the TSliderClientScript to set the TSlider event handlers.
- *
- * The slider on the client-side supports the following events.
- * # <tt>OnSliderMove</tt> -- raised when the slider is moved.
- * # <tt>OnSliderChanged</tt> -- raised when the slider value is changed
- *
- * You can attach custom javascript code to each of these events
- *
- * @return TSliderClientScript javascript validator event options.
- */
- public function getClientSide()
- {
- if($this->_clientScript===null)
- $this->_clientScript = $this->createClientScript();
- return $this->_clientScript;
- }
-
- /**
- * @return TSliderClientScript javascript event options.
- */
- protected function createClientScript()
- {
- return new TSliderClientScript;
- }
-
- /**
- * @return string the HTML tag name for slider. Defaults to div.
- */
- public function getTagName ()
- {
- return "div";
- }
-
- /**
- * Add the specified css classes to the track
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- if ($this->getCssClass()==='')
- {
- $class=($this->getDirection()==TSliderDirection::Horizontal)?'HorizontalSlider':'VerticalSlider';
- $writer->addAttribute('class', 'Slider '.$class);
- }
-
- }
-
- /**
- * Render the body content
- */
- public function renderContents($writer)
- {
- // Render the 'Track'
- $writer->addAttribute('class', 'Track');
- $writer->addAttribute('id', $this->getClientID().'_track');
- $writer->renderBeginTag('div');
- // Render the 'Progress Indicator'
- if ($this->getProgressIndicator())
- {
- $writer->addAttribute('class', 'Progress');
- $writer->addAttribute('id', $this->getClientID().'_progress');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- // Render the 'Ruler'
- /*
- * Removing for now
- $writer->addAttribute('class', 'RuleContainer');
- $writer->addAttribute('id', $this->getClientID()."_rule");
- $writer->renderBeginTag('div');
- for ($i=0;$i<=100;$i+=10)
- {
- $writer->addAttribute('class', 'RuleMark');
- $attr=($this->getDirection()===TSliderDirection::Horizontal)?"left":"top";
- $writer->addStyleAttribute($attr, $i.'%');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- $writer->renderEndTag();
- */
-
- $writer->renderEndTag();
-
- // Render the 'Handle'
- $writer->addAttribute('class', 'Handle');
- $writer->addAttribute('id', $this->getClientID().'_handle');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender ($param)
- {
- parent::onPreRender($param);
- $this->registerStyleSheet();
- $this->registerSliderClientScript();
-
- }
-
- /**
- * Registers the CSS relevant to the TSlider.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- if(($url=$this->getCssUrl())==='')
- {
- $manager=$this->getApplication()->getAssetManager();
- // publish the assets
- $url=$manager->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'TSlider');
- $url.='/TSlider.css';
- }
- $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
- }
-
- /**
- * Registers the javascript code to initialize the slider.
- */
- protected function registerSliderClientScript()
- {
- $page=$this->getPage();
- $cs = $page->getClientScript();
- $cs->registerPradoScript("slider");
- $id=$this->getClientID();
- $cs->registerHiddenField($id.'_1',$this->getValue());
- $page->registerRequiresPostData($this);
- $cs->registerPostBackControl($this->getClientClassName(),$this->getSliderOptions());
- }
-
- /**
- * Get javascript sliderr options.
- * @return array slider client-side options
- */
- protected function getSliderOptions()
- {
- // PostBack Options :
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['AutoPostBack'] = $this->getAutoPostBack();
-
- // Slider Control options
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
- $options['axis'] = strtolower($this->getDirection());
- $options['maximum'] = $maxValue;
- $options['minimum'] = $minValue;
- $options['range'] = TJavascript::quoteJsLiteral('$R('.$minValue.",".$maxValue.")");
- $options['sliderValue'] = $this->getValue();
- $options['disabled'] = !$this->getEnabled();
- $values=$this->getValues();
- if (!empty($values))
- {
- // Values are provided. Check if min/max are present in them
- if (!in_array($minValue, $values)) $values[]=$minValue;
- if (!in_array($maxValue, $values)) $values[]=$maxValue;
- // Remove all values outsize the range [min..max]
- foreach ($values as $idx=>$value)
- {
- if ($value < $minValue) unset ($values[$idx]);
- if ($value > $maxValue) unset ($values[$idx]);
- }
- }
- else
- {
- // Values are not provided, generate automatically using stepsize
- $step=$this->getStepSize();
- // We want at most self::MAX_STEPS values, so, change the step if necessary
- if (($maxValue-$minValue)/$step > self::MAX_STEPS)
- {
- $step=($maxValue-$minValue)/self::MAX_STEPS;
- }
- $values=array();
- for ($i=$minValue;$i<=$maxValue;$i+=$step)
- $values[]=$i;
- // Add max if it's not in the array because of step
- if (!in_array($maxValue, $values)) $values[]=$maxValue;
- }
- $options['values'] = $values;
- if($this->_clientScript!==null)
- $options = array_merge($options,$this->_clientScript->getOptions()->toArray());
- return $options;
- }
-}
-
-/**
- * TSliderClientScript class.
- *
- * Client-side slider events {@link setOnChange OnChange} and {@line setOnMove OnMove}
- * can be modified through the {@link TSlider:: getClientSide ClientSide}
- * property of a slider.
- *
- * The current value of the slider can be get in the 'value' js variable
- *
- * The <tt>OnMove</tt> event is raised when the slider moves
- * The <tt>OnChange</tt> event is raised when the slider value is changed (or at the end of a move)
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSliderClientScript extends TClientSideOptions
-{
- /**
- * Javascript code to execute when the slider value is changed.
- * @param string javascript code
- */
- public function setOnChange($javascript)
- {
- $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
- $this->setFunction('onChange', $code);
- }
-
- /**
- * @return string javascript code to execute when the slider value is changed.
- */
- public function getOnChange()
- {
- return $this->getOption('onChange');
- }
-
- /* Javascript code to execute when the slider moves.
- * @param string javascript code
- */
- public function setOnSlide($javascript)
- {
- $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
- $this->setFunction('onSlide', $code);
- }
-
- /**
- * @return string javascript code to execute when the slider moves.
- */
- public function getOnSlide()
- {
- return $this->getOption('onSlide');
- }
-}
-
-
-/**
- * TSliderDirection class.
- *
- * TSliderDirection defines the enumerable type for the possible direction that can be used in a {@link TSlider}
- *
- * The following enumerable values are defined :
- * - Horizontal : Horizontal slider
- * - Vertical : Vertical slider
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSliderDirection extends TEnumerable
-{
- const Horizontal='Horizontal';
- const Vertical='Vertical';
-}
-
-
+<?php +/** + * TSlider class file. + * + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * TSlider class + * + * TSlider displays a slider for numeric input purpose. A slider consists of a 'track', + * which define the range of possible value, and a 'handle' which can slide on the track, to select + * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction} + * property. By default, it's horizontal. + * + * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties. + * The default range is from 0 to 100. + * The {@link SetStepSize StepSize} property can be used to define the <b>step</b> between 2 values inside the range. + * Notice that this step will be recomputed if there is more than 200 values between the range boundaries. + * You can also provide the allowed values by setting the {@link SetValues Values} array. + * + * A 'Progress Indicator' can be displayed within the track with the {@link SetProgressIndicator ProgressIndicator} property. + * + * The TSlider control can be easily customized using CssClasses. You can provide your own css file, using the + * {@link SetCssUrl CssUrl} property. + * The css class for TSlider can be set by the {@link setCssClass CssClass} property. Default value is "Slider HorizontalSlider" + * for an horizontal slider, and "Slider VerticalSlider" for a vertical one. + * + * If {@link SetAutoPostBack AutoPostBack} property is true, postback is sent as soon as the value changed. + * + * TSlider raises the {@link onValueChanged} event when the value of the slider has changed during postback. + * + * You can also attach ClientSide javascript events handler to the slider : + * - ClientSide.onSlide is called when the handle is slided on the track. You can get the current value in the <b>value</b> + * javascript variable. You can use this event to update on client side a label with the current value + * - ClientSide.onChange is called when the slider value has changed (at the end of a move). + * + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TSlider extends TWebControl implements IPostBackDataHandler, IDataRenderer +{ + const MAX_STEPS=200; + /** + * @var TSliderHandle handle component + */ + private $_handle; + /* + * @var boolean Wether the data has changed during postback + */ + private $_dataChanged=false; + /** + * @var TSliderClientScript Clients side javascripts + */ + private $_clientScript=null; + + /** + * @return TSliderDirection Direction of slider (Horizontal or Vertical). Defaults to Horizontal. + */ + public function getDirection() + { + return $this->getViewState('Direction', TSliderDirection::Horizontal); + } + + /** + * @param TSliderDirection Direction of slider (Horizontal or Vertical) + */ + public function setDirection($value) + { + $this->setViewState('Direction', TPropertyValue::ensureEnum($value,'TSliderDirection'),TSliderDirection::Horizontal); + } + + /** + * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to '' (a default CSS file will be applied in this case.) + */ + public function getCssUrl() + { + return $this->getViewState('CssUrl',''); + } + + /** + * @param string URL for the CSS file including all relevant CSS class definitions. + */ + public function setCssUrl($value) + { + $this->setViewState('CssUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return float Maximum value for the slider. Defaults to 100.0. + */ + public function getMaxValue() + { + return $this->getViewState('MaxValue',100.0); + } + + /** + * @param float Maximum value for slider + */ + public function setMaxValue($value) + { + $this->setViewState('MaxValue', TPropertyValue::ensureFloat($value),100.0); + } + + /** + * @return float Minimum value for slider. Defaults to 0.0. + */ + public function getMinValue() + { + return $this->getViewState('MinValue',0.0); + } + + /** + * @param float Minimum value for slider + */ + public function setMinValue($value) + { + $this->setViewState('MinValue', TPropertyValue::ensureFloat($value),0.0); + } + + /** + * @return float Step size. Defaults to 1.0. + */ + public function getStepSize() + { + return $this->getViewState('StepSize', 1.0); + } + + /** + * Sets the step size used to determine the places where the slider handle can stop at. + * An evenly distributed stop marks will be generated according to + * {@link getMinValue MinValue}, {@link getMaxValue MaxValue} and StepSize. + * To use uneven stop marks, set {@link setValues Values}. + * @param float Step size. + */ + public function setStepSize($value) + { + $this->setViewState('StepSize', $value, 1.0); + } + + /** + * @return boolean wether to display a progress indicator or not. Defaults to true. + */ + public function getProgressIndicator () + { + return $this->getViewState('ProgressIndicator', true); + } + + /** + * @param boolean wether to display a progress indicator or not. Defaults to true. + */ + public function setProgressIndicator ($value) + { + $this->setViewState('ProgressIndicator', TPropertyValue::ensureBoolean($value), true); + } + /** + * @return float current value of slider + */ + public function getValue() + { + return $this->getViewState('Value',0.0); + } + + /** + * @param float current value of slider + */ + public function setValue($value) + { + $this->setViewState('Value', TPropertyValue::ensureFloat($value),0.0); + } + + /** + * Returns the value of the TSlider control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getValue()}. + * @return string the value of the TSlider control. + * @see getValue + */ + public function getData() + { + return $this->getValue(); + } + + /** + * Sets the value of the TSlider control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setValue()}. + * @param string the value of the TSlider control. + * @see setValue + */ + public function setData($value) + { + $this->setValue($value); + } + + /** + * @return array list of allowed values the slider can take. Defaults to an empty array. + */ + public function getValues() + { + return $this->getViewState('Values', array()); + } + + /** + * Sets the possible values that the slider can take. + * If this is set, {@link setStepSize StepSize} will be ignored. The latter + * generates a set of evenly distributed candidate values. + * @param array list of allowed values the slider can take + */ + public function setValues($value) + { + $this->setViewState('Values', TPropertyValue::ensureArray($value), array()); + } + + /** + * @return boolean a value indicating whether an automatic postback to the server + * will occur whenever the user modifies the slider value. Defaults to false. + */ + public function getAutoPostBack() + { + return $this->getViewState('AutoPostBack',false); + } + + /** + * Sets the value indicating if postback automatically. + * An automatic postback to the server will occur whenever the user + * modifies the slider value. + * @param boolean the value indicating if postback automatically + */ + public function setAutoPostBack($value) + { + $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TSlider'; + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getValue Value} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onValueChanged(null); + } + + /** + * Raises <b>OnValueChanged</b> event. + * This method is invoked when the {@link getValue Value} + * property changes on postback. + * If you override this method, be sure to call the parent implementation to ensure + * the invocation of the attached event handlers. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onValueChanged($param) + { + $this->raiseEvent('OnValueChanged',$this,$param); + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + $value=(float)$values[$this->getClientID().'_1']; + if($this->getValue()!==$value) + { + $this->setValue($value); + return $this->_dataChanged=true; + } + else + return false; + } + + /** + * Gets the TSliderClientScript to set the TSlider event handlers. + * + * The slider on the client-side supports the following events. + * # <tt>OnSliderMove</tt> -- raised when the slider is moved. + * # <tt>OnSliderChanged</tt> -- raised when the slider value is changed + * + * You can attach custom javascript code to each of these events + * + * @return TSliderClientScript javascript validator event options. + */ + public function getClientSide() + { + if($this->_clientScript===null) + $this->_clientScript = $this->createClientScript(); + return $this->_clientScript; + } + + /** + * @return TSliderClientScript javascript event options. + */ + protected function createClientScript() + { + return new TSliderClientScript; + } + + /** + * @return string the HTML tag name for slider. Defaults to div. + */ + public function getTagName () + { + return "div"; + } + + /** + * Add the specified css classes to the track + * @param THtmlWriter writer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + if ($this->getCssClass()==='') + { + $class=($this->getDirection()==TSliderDirection::Horizontal)?'HorizontalSlider':'VerticalSlider'; + $writer->addAttribute('class', 'Slider '.$class); + } + + } + + /** + * Render the body content + */ + public function renderContents($writer) + { + // Render the 'Track' + $writer->addAttribute('class', 'Track'); + $writer->addAttribute('id', $this->getClientID().'_track'); + $writer->renderBeginTag('div'); + // Render the 'Progress Indicator' + if ($this->getProgressIndicator()) + { + $writer->addAttribute('class', 'Progress'); + $writer->addAttribute('id', $this->getClientID().'_progress'); + $writer->renderBeginTag('div'); + $writer->renderEndTag(); + } + // Render the 'Ruler' + /* + * Removing for now + $writer->addAttribute('class', 'RuleContainer'); + $writer->addAttribute('id', $this->getClientID()."_rule"); + $writer->renderBeginTag('div'); + for ($i=0;$i<=100;$i+=10) + { + $writer->addAttribute('class', 'RuleMark'); + $attr=($this->getDirection()===TSliderDirection::Horizontal)?"left":"top"; + $writer->addStyleAttribute($attr, $i.'%'); + $writer->renderBeginTag('div'); + $writer->renderEndTag(); + } + $writer->renderEndTag(); + */ + + $writer->renderEndTag(); + + // Render the 'Handle' + $writer->addAttribute('class', 'Handle'); + $writer->addAttribute('id', $this->getClientID().'_handle'); + $writer->renderBeginTag('div'); + $writer->renderEndTag(); + } + /** + * Registers CSS and JS. + * This method is invoked right before the control rendering, if the control is visible. + * @param mixed event parameter + */ + public function onPreRender ($param) + { + parent::onPreRender($param); + $this->registerStyleSheet(); + $this->registerSliderClientScript(); + + } + + /** + * Registers the CSS relevant to the TSlider. + * It will register the CSS file specified by {@link getCssUrl CssUrl}. + * If that is not set, it will use the default CSS. + */ + protected function registerStyleSheet() + { + if(($url=$this->getCssUrl())==='') + { + $manager=$this->getApplication()->getAssetManager(); + // publish the assets + $url=$manager->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'TSlider'); + $url.='/TSlider.css'; + } + $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url); + } + + /** + * Registers the javascript code to initialize the slider. + */ + protected function registerSliderClientScript() + { + $page=$this->getPage(); + $cs = $page->getClientScript(); + $cs->registerPradoScript("slider"); + $id=$this->getClientID(); + $cs->registerHiddenField($id.'_1',$this->getValue()); + $page->registerRequiresPostData($this); + $cs->registerPostBackControl($this->getClientClassName(),$this->getSliderOptions()); + } + + /** + * Get javascript sliderr options. + * @return array slider client-side options + */ + protected function getSliderOptions() + { + // PostBack Options : + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + $options['AutoPostBack'] = $this->getAutoPostBack(); + + // Slider Control options + $minValue=$this->getMinValue(); + $maxValue=$this->getMaxValue(); + $options['axis'] = strtolower($this->getDirection()); + $options['maximum'] = $maxValue; + $options['minimum'] = $minValue; + $options['range'] = TJavascript::quoteJsLiteral('$R('.$minValue.",".$maxValue.")"); + $options['sliderValue'] = $this->getValue(); + $options['disabled'] = !$this->getEnabled(); + $values=$this->getValues(); + if (!empty($values)) + { + // Values are provided. Check if min/max are present in them + if (!in_array($minValue, $values)) $values[]=$minValue; + if (!in_array($maxValue, $values)) $values[]=$maxValue; + // Remove all values outsize the range [min..max] + foreach ($values as $idx=>$value) + { + if ($value < $minValue) unset ($values[$idx]); + if ($value > $maxValue) unset ($values[$idx]); + } + } + else + { + // Values are not provided, generate automatically using stepsize + $step=$this->getStepSize(); + // We want at most self::MAX_STEPS values, so, change the step if necessary + if (($maxValue-$minValue)/$step > self::MAX_STEPS) + { + $step=($maxValue-$minValue)/self::MAX_STEPS; + } + $values=array(); + for ($i=$minValue;$i<=$maxValue;$i+=$step) + $values[]=$i; + // Add max if it's not in the array because of step + if (!in_array($maxValue, $values)) $values[]=$maxValue; + } + $options['values'] = $values; + if($this->_clientScript!==null) + $options = array_merge($options,$this->_clientScript->getOptions()->toArray()); + return $options; + } +} + +/** + * TSliderClientScript class. + * + * Client-side slider events {@link setOnChange OnChange} and {@line setOnMove OnMove} + * can be modified through the {@link TSlider:: getClientSide ClientSide} + * property of a slider. + * + * The current value of the slider can be get in the 'value' js variable + * + * The <tt>OnMove</tt> event is raised when the slider moves + * The <tt>OnChange</tt> event is raised when the slider value is changed (or at the end of a move) + * + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TSliderClientScript extends TClientSideOptions +{ + /** + * Javascript code to execute when the slider value is changed. + * @param string javascript code + */ + public function setOnChange($javascript) + { + $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }"); + $this->setFunction('onChange', $code); + } + + /** + * @return string javascript code to execute when the slider value is changed. + */ + public function getOnChange() + { + return $this->getOption('onChange'); + } + + /* Javascript code to execute when the slider moves. + * @param string javascript code + */ + public function setOnSlide($javascript) + { + $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }"); + $this->setFunction('onSlide', $code); + } + + /** + * @return string javascript code to execute when the slider moves. + */ + public function getOnSlide() + { + return $this->getOption('onSlide'); + } +} + + +/** + * TSliderDirection class. + * + * TSliderDirection defines the enumerable type for the possible direction that can be used in a {@link TSlider} + * + * The following enumerable values are defined : + * - Horizontal : Horizontal slider + * - Vertical : Vertical slider + * + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ +class TSliderDirection extends TEnumerable +{ + const Horizontal='Horizontal'; + const Vertical='Vertical'; +} + + diff --git a/framework/Web/UI/WebControls/TStatements.php b/framework/Web/UI/WebControls/TStatements.php index c3f43278..dd7631e2 100644 --- a/framework/Web/UI/WebControls/TStatements.php +++ b/framework/Web/UI/WebControls/TStatements.php @@ -1,63 +1,63 @@ -<?php
-/**
- * TStatements class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TStatements class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TStatements class
- *
- * TStatements executes one or several PHP statements and renders the display
- * generated during the execution. The execution happens during the rendering stage.
- * The PHP statements being executed can be set via the property
- * {@link setStatements Statements}. The context of the statemenets executed
- * is the TStatements object itself.
- *
- * Note, since TStatements allows execution of arbitrary PHP statements,
- * make sure {@link setStatements Statements} does not come directly from user input.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TStatements extends TControl
-{
- /**
- * @var string PHP statements
- */
- private $_s='';
-
- /**
- * @return string the statements to be executed
- */
- public function getStatements()
- {
- return $this->_s;
- }
-
- /**
- * @param string the PHP statements to be executed
- */
- public function setStatements($value)
- {
- $this->_s=$value;
- }
-
- /**
- * Renders the evaluation result of the statements.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_s!=='')
- $writer->write($this->evaluateStatements($this->_s));
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TStatements class + * + * TStatements executes one or several PHP statements and renders the display + * generated during the execution. The execution happens during the rendering stage. + * The PHP statements being executed can be set via the property + * {@link setStatements Statements}. The context of the statemenets executed + * is the TStatements object itself. + * + * Note, since TStatements allows execution of arbitrary PHP statements, + * make sure {@link setStatements Statements} does not come directly from user input. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TStatements extends TControl +{ + /** + * @var string PHP statements + */ + private $_s=''; + + /** + * @return string the statements to be executed + */ + public function getStatements() + { + return $this->_s; + } + + /** + * @param string the PHP statements to be executed + */ + public function setStatements($value) + { + $this->_s=$value; + } + + /** + * Renders the evaluation result of the statements. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function render($writer) + { + if($this->_s!=='') + $writer->write($this->evaluateStatements($this->_s)); + } +} + diff --git a/framework/Web/UI/WebControls/TStyle.php b/framework/Web/UI/WebControls/TStyle.php index 58be223a..93f7d45d 100644 --- a/framework/Web/UI/WebControls/TStyle.php +++ b/framework/Web/UI/WebControls/TStyle.php @@ -1,893 +1,893 @@ -<?php
-/**
- * TStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TFont definition
- */
-Prado::using('System.Web.UI.WebControls.TFont');
-
-/**
- * TStyle class
- *
- * TStyle encapsulates the CSS style applied to a control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TStyle extends TComponent
-{
- /**
- * @var array storage of CSS fields
- */
- private $_fields=array();
- /**
- * @var TFont font object
- */
- private $_font=null;
- /**
- * @var string CSS class name
- */
- private $_class=null;
- /**
- * @var string CSS style string (those not represented by specific fields of TStyle)
- */
- private $_customStyle=null;
- /**
- * @var string display style
- */
- private $_displayStyle='Fixed';
-
- /**
- * Constructor.
- * @param TStyle style to copy from
- */
- public function __construct($style=null)
- {
- if($style!==null)
- $this->copyFrom($style);
- }
-
- /**
- * Need to clone the font object.
- */
- public function __clone()
- {
- if($this->_font!==null)
- $this->_font = clone($this->_font);
- }
-
- /**
- * @return string the background color of the control
- */
- public function getBackColor()
- {
- return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
- }
-
- /**
- * @param string the background color of the control
- */
- public function setBackColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['background-color']);
- else
- $this->_fields['background-color']=$value;
- }
-
- /**
- * @return string the border color of the control
- */
- public function getBorderColor()
- {
- return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
- }
-
- /**
- * @param string the border color of the control
- */
- public function setBorderColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-color']);
- else
- $this->_fields['border-color']=$value;
- }
-
- /**
- * @return string the border style of the control
- */
- public function getBorderStyle()
- {
- return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
- }
-
- /**
- * Sets the border style of the control.
- * @param string the border style of the control
- */
- public function setBorderStyle($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-style']);
- else
- $this->_fields['border-style']=$value;
- }
-
- /**
- * @return string the border width of the control
- */
- public function getBorderWidth()
- {
- return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
- }
-
- /**
- * @param string the border width of the control
- */
- public function setBorderWidth($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-width']);
- else
- $this->_fields['border-width']=$value;
- }
-
- /**
- * @return string the CSS class of the control
- */
- public function getCssClass()
- {
- return $this->_class===null?'':$this->_class;
- }
-
- /**
- * @return boolean true if CSS is set or empty.
- */
- public function hasCssClass()
- {
- return ($this->_class!==null);
- }
-
- /**
- * @param string the name of the CSS class of the control
- */
- public function setCssClass($value)
- {
- $this->_class=$value;
- }
-
- /**
- * @return TFont the font of the control
- */
- public function getFont()
- {
- if($this->_font===null)
- $this->_font=new TFont;
- return $this->_font;
- }
-
- /**
- * @return boolean true if font is set.
- */
- public function hasFont()
- {
- return $this->_font !== null;
- }
-
- /**
- * @param TDisplayStyle control display style, default is TDisplayStyle::Fixed
- */
- public function setDisplayStyle($value)
- {
- $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
- switch($this->_displayStyle)
- {
- case TDisplayStyle::None:
- $this->_fields['display'] = 'none';
- break;
- case TDisplayStyle::Dynamic:
- $this->_fields['display'] = ''; //remove the display property
- break;
- case TDisplayStyle::Fixed:
- $this->_fields['visibility'] = 'visible';
- break;
- case TDisplayStyle::Hidden:
- $this->_fields['visibility'] = 'hidden';
- break;
- }
- }
-
- /**
- * @return TDisplayStyle display style
- */
- public function getDisplayStyle()
- {
- return $this->_displayStyle;
- }
-
- /**
- * @return string the foreground color of the control
- */
- public function getForeColor()
- {
- return isset($this->_fields['color'])?$this->_fields['color']:'';
- }
-
- /**
- * @param string the foreground color of the control
- */
- public function setForeColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['color']);
- else
- $this->_fields['color']=$value;
- }
-
- /**
- * @return string the height of the control
- */
- public function getHeight()
- {
- return isset($this->_fields['height'])?$this->_fields['height']:'';
- }
-
- /**
- * @param string the height of the control
- */
- public function setHeight($value)
- {
- if(trim($value)==='')
- unset($this->_fields['height']);
- else
- $this->_fields['height']=$value;
- }
-
- /**
- * @return string the custom style of the control
- */
- public function getCustomStyle()
- {
- return $this->_customStyle===null?'':$this->_customStyle;
- }
-
- /**
- * Sets custom style fields from a string.
- * Custom style fields will be overwritten by style fields explicitly defined.
- * @param string the custom style of the control
- */
- public function setCustomStyle($value)
- {
- $this->_customStyle=$value;
- }
-
- /**
- * @return string a single style field value set via {@link setStyleField}. Defaults to empty string.
- */
- public function getStyleField($name)
- {
- return isset($this->_fields[$name])?$this->_fields[$name]:'';
- }
-
- /**
- * Sets a single style field value.
- * Style fields set by this method will overwrite those set by {@link setCustomStyle}.
- * @param string style field name
- * @param string style field value
- */
- public function setStyleField($name,$value)
- {
- $this->_fields[$name]=$value;
- }
-
- /**
- * Clears a single style field value;
- * @param string style field name
- */
- public function clearStyleField($name)
- {
- unset($this->_fields[$name]);
- }
-
- /**
- * @return boolean whether a style field has been defined by {@link setStyleField}
- */
- public function hasStyleField($name)
- {
- return isset($this->_fields[$name]);
- }
-
- /**
- * @return string the width of the control
- */
- public function getWidth()
- {
- return isset($this->_fields['width'])?$this->_fields['width']:'';
- }
-
- /**
- * @param string the width of the control
- */
- public function setWidth($value)
- {
- $this->_fields['width']=$value;
- }
-
- /**
- * Resets the style to the original empty state.
- */
- public function reset()
- {
- $this->_fields=array();
- $this->_font=null;
- $this->_class=null;
- $this->_customStyle=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- if($style instanceof TStyle)
- {
- $this->_fields=array_merge($this->_fields,$style->_fields);
- if($style->_class!==null)
- $this->_class=$style->_class;
- if($style->_customStyle!==null)
- $this->_customStyle=$style->_customStyle;
- if($style->_font!==null)
- $this->getFont()->copyFrom($style->_font);
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- if($style instanceof TStyle)
- {
- $this->_fields=array_merge($style->_fields,$this->_fields);
- if($this->_class===null)
- $this->_class=$style->_class;
- if($this->_customStyle===null)
- $this->_customStyle=$style->_customStyle;
- if($style->_font!==null)
- $this->getFont()->mergeWith($style->_font);
- }
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if($this->_customStyle!==null)
- {
- foreach(explode(';',$this->_customStyle) as $style)
- {
- $arr=explode(':',$style,2);
- if(isset($arr[1]) && trim($arr[0])!=='')
- $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
- }
- }
- $writer->addStyleAttributes($this->_fields);
- if($this->_font!==null)
- $this->_font->addAttributesToRender($writer);
- if($this->_class!==null)
- $writer->addAttribute('class',$this->_class);
- }
-
- /**
- * @return array list of style fields.
- */
- public function getStyleFields()
- {
- return $this->_fields;
- }
-}
-
-/**
- * TDisplayStyle defines the enumerable type for the possible styles
- * that a web control can display.
- *
- * The following enumerable values are defined:
- * - None: the control is not displayed and not included in the layout.
- * - Dynamic: the control is displayed and included in the layout, the layout flow is dependent on the control (equivalent to display:'' in css).
- * - Fixed: Similar to Dynamic with CSS "visibility" set "shown".
- * - Hidden: the control is not displayed and is included in the layout.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TDisplayStyle extends TEnumerable
-{
- const None='None';
- const Dynamic='Dynamic';
- const Fixed='Fixed';
- const Hidden='Hidden';
-}
-
-/**
- * TTableStyle class.
- * TTableStyle represents the CSS style specific for HTML table.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableStyle extends TStyle
-{
- /**
- * @var TVerticalAlign the URL of the background image for the table
- */
- private $_backImageUrl=null;
- /**
- * @var THorizontalAlign horizontal alignment of the contents within the table
- */
- private $_horizontalAlign=null;
- /**
- * @var integer cellpadding of the table
- */
- private $_cellPadding=null;
- /**
- * @var integer cellspacing of the table
- */
- private $_cellSpacing=null;
- /**
- * @var TTableGridLines grid line setting of the table
- */
- private $_gridLines=null;
- /**
- * @var boolean whether the table border should be collapsed
- */
- private $_borderCollapse=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TTableStyle specific attributes.
- */
- public function reset()
- {
- $this->_backImageUrl=null;
- $this->_horizontalAlign=null;
- $this->_cellPadding=null;
- $this->_cellSpacing=null;
- $this->_gridLines=null;
- $this->_borderCollapse=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TTableStyle)
- {
- if($style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_cellPadding!==null)
- $this->_cellPadding=$style->_cellPadding;
- if($style->_cellSpacing!==null)
- $this->_cellSpacing=$style->_cellSpacing;
- if($style->_gridLines!==null)
- $this->_gridLines=$style->_gridLines;
- if($style->_borderCollapse!==null)
- $this->_borderCollapse=$style->_borderCollapse;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TTableStyle)
- {
- if($this->_backImageUrl===null && $style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_cellPadding===null && $style->_cellPadding!==null)
- $this->_cellPadding=$style->_cellPadding;
- if($this->_cellSpacing===null && $style->_cellSpacing!==null)
- $this->_cellSpacing=$style->_cellSpacing;
- if($this->_gridLines===null && $style->_gridLines!==null)
- $this->_gridLines=$style->_gridLines;
- if($this->_borderCollapse===null && $style->_borderCollapse!==null)
- $this->_borderCollapse=$style->_borderCollapse;
- }
- }
-
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(($url=trim($this->getBackImageUrl()))!=='')
- $writer->addStyleAttribute('background-image','url('.$url.')');
-
- if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
-
- if(($cellPadding=$this->getCellPadding())>=0)
- $writer->addAttribute('cellpadding',"$cellPadding");
-
- if(($cellSpacing=$this->getCellSpacing())>=0)
- $writer->addAttribute('cellspacing',"$cellSpacing");
-
- if($this->getBorderCollapse())
- $writer->addStyleAttribute('border-collapse','collapse');
-
- switch($this->getGridLines())
- {
- case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
- case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
- case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
- }
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string the URL of the background image for the table
- */
- public function getBackImageUrl()
- {
- return $this->_backImageUrl===null?'':$this->_backImageUrl;
- }
-
- /**
- * Sets the URL of the background image for the table
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->_backImageUrl=$value;
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the table, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return integer cellpadding of the table. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- return $this->_cellPadding===null?-1:$this->_cellPadding;
- }
-
- /**
- * @param integer cellpadding of the table. A value equal to -1 clears up the setting.
- * @throws TInvalidDataValueException if the value is less than -1.
- */
- public function setCellPadding($value)
- {
- if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
- throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
- }
-
- /**
- * @return integer cellspacing of the table. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- return $this->_cellSpacing===null?-1:$this->_cellSpacing;
- }
-
- /**
- * @param integer cellspacing of the table. A value equal to -1 clears up the setting.
- * @throws TInvalidDataValueException if the value is less than -1.
- */
- public function setCellSpacing($value)
- {
- if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
- throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
- }
-
- /**
- * Sets the grid line style of the table.
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
- }
-
-
- /**
- * @return boolean whether the table borders should be collapsed. Defaults to false.
- */
- public function getBorderCollapse()
- {
- return $this->_borderCollapse===null?false:$this->_borderCollapse;
- }
-
- /**
- * @param boolean whether the table borders should be collapsed.
- */
- public function setBorderCollapse($value)
- {
- $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * TTableItemStyle class.
- * TTableItemStyle represents the CSS style specific for HTML table item.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableItemStyle extends TStyle
-{
- /**
- * @var THorizontalAlign horizontal alignment of the contents within the table item
- */
- private $_horizontalAlign=null;
- /**
- * @var TVerticalAlign vertical alignment of the contents within the table item
- */
- private $_verticalAlign=null;
- /**
- * @var boolean whether the content wraps within the table item
- */
- private $_wrap=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TTableItemStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_verticalAlign=null;
- $this->_horizontalAlign=null;
- $this->_wrap=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TTableItemStyle)
- {
- if($this->_verticalAlign===null && $style->_verticalAlign!==null)
- $this->_verticalAlign=$style->_verticalAlign;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_wrap===null && $style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TTableItemStyle)
- {
- if($style->_verticalAlign!==null)
- $this->_verticalAlign=$style->_verticalAlign;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(!$this->getWrap())
- $writer->addStyleAttribute('white-space','nowrap');
-
- if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $writer->addAttribute('align',strtolower($horizontalAlign));
-
- if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
- $writer->addAttribute('valign',strtolower($verticalAlign));
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the table item, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return TVerticalAlign the vertical alignment of the contents within the table item, defaults to TVerticalAlign::NotSet.
- */
- public function getVerticalAlign()
- {
- return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * @param TVerticalAlign the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
- }
-
- /**
- * @return boolean whether the content wraps within the table item. Defaults to true.
- */
- public function getWrap()
- {
- return $this->_wrap===null?true:$this->_wrap;
- }
-
- /**
- * Sets the value indicating whether the content wraps within the table item.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->_wrap=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * THorizontalAlign class.
- * THorizontalAlign defines the enumerable type for the possible horizontal alignments in a CSS style.
- *
- * The following enumerable values are defined:
- * - NotSet: the alignment is not specified.
- * - Left: left aligned
- * - Right: right aligned
- * - Center: center aligned
- * - Justify: the begin and end are justified
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class THorizontalAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Left='Left';
- const Right='Right';
- const Center='Center';
- const Justify='Justify';
-}
-
-/**
- * TVerticalAlign class.
- * TVerticalAlign defines the enumerable type for the possible vertical alignments in a CSS style.
- *
- * The following enumerable values are defined:
- * - NotSet: the alignment is not specified.
- * - Top: top aligned
- * - Bottom: bottom aligned
- * - Middle: middle aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TVerticalAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Top='Top';
- const Bottom='Bottom';
- const Middle='Middle';
-}
-
-
-/**
- * TTableGridLines class.
- * TTableGridLines defines the enumerable type for the possible grid line types of an HTML table.
- *
- * The following enumerable values are defined:
- * - None: no grid lines
- * - Horizontal: horizontal grid lines only
- * - Vertical: vertical grid lines only
- * - Both: both horizontal and vertical grid lines are shown
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableGridLines extends TEnumerable
-{
- const None='None';
- const Horizontal='Horizontal';
- const Vertical='Vertical';
- const Both='Both';
-}
-
+<?php +/** + * TStyle class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TFont definition + */ +Prado::using('System.Web.UI.WebControls.TFont'); + +/** + * TStyle class + * + * TStyle encapsulates the CSS style applied to a control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TStyle extends TComponent +{ + /** + * @var array storage of CSS fields + */ + private $_fields=array(); + /** + * @var TFont font object + */ + private $_font=null; + /** + * @var string CSS class name + */ + private $_class=null; + /** + * @var string CSS style string (those not represented by specific fields of TStyle) + */ + private $_customStyle=null; + /** + * @var string display style + */ + private $_displayStyle='Fixed'; + + /** + * Constructor. + * @param TStyle style to copy from + */ + public function __construct($style=null) + { + if($style!==null) + $this->copyFrom($style); + } + + /** + * Need to clone the font object. + */ + public function __clone() + { + if($this->_font!==null) + $this->_font = clone($this->_font); + } + + /** + * @return string the background color of the control + */ + public function getBackColor() + { + return isset($this->_fields['background-color'])?$this->_fields['background-color']:''; + } + + /** + * @param string the background color of the control + */ + public function setBackColor($value) + { + if(trim($value)==='') + unset($this->_fields['background-color']); + else + $this->_fields['background-color']=$value; + } + + /** + * @return string the border color of the control + */ + public function getBorderColor() + { + return isset($this->_fields['border-color'])?$this->_fields['border-color']:''; + } + + /** + * @param string the border color of the control + */ + public function setBorderColor($value) + { + if(trim($value)==='') + unset($this->_fields['border-color']); + else + $this->_fields['border-color']=$value; + } + + /** + * @return string the border style of the control + */ + public function getBorderStyle() + { + return isset($this->_fields['border-style'])?$this->_fields['border-style']:''; + } + + /** + * Sets the border style of the control. + * @param string the border style of the control + */ + public function setBorderStyle($value) + { + if(trim($value)==='') + unset($this->_fields['border-style']); + else + $this->_fields['border-style']=$value; + } + + /** + * @return string the border width of the control + */ + public function getBorderWidth() + { + return isset($this->_fields['border-width'])?$this->_fields['border-width']:''; + } + + /** + * @param string the border width of the control + */ + public function setBorderWidth($value) + { + if(trim($value)==='') + unset($this->_fields['border-width']); + else + $this->_fields['border-width']=$value; + } + + /** + * @return string the CSS class of the control + */ + public function getCssClass() + { + return $this->_class===null?'':$this->_class; + } + + /** + * @return boolean true if CSS is set or empty. + */ + public function hasCssClass() + { + return ($this->_class!==null); + } + + /** + * @param string the name of the CSS class of the control + */ + public function setCssClass($value) + { + $this->_class=$value; + } + + /** + * @return TFont the font of the control + */ + public function getFont() + { + if($this->_font===null) + $this->_font=new TFont; + return $this->_font; + } + + /** + * @return boolean true if font is set. + */ + public function hasFont() + { + return $this->_font !== null; + } + + /** + * @param TDisplayStyle control display style, default is TDisplayStyle::Fixed + */ + public function setDisplayStyle($value) + { + $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle'); + switch($this->_displayStyle) + { + case TDisplayStyle::None: + $this->_fields['display'] = 'none'; + break; + case TDisplayStyle::Dynamic: + $this->_fields['display'] = ''; //remove the display property + break; + case TDisplayStyle::Fixed: + $this->_fields['visibility'] = 'visible'; + break; + case TDisplayStyle::Hidden: + $this->_fields['visibility'] = 'hidden'; + break; + } + } + + /** + * @return TDisplayStyle display style + */ + public function getDisplayStyle() + { + return $this->_displayStyle; + } + + /** + * @return string the foreground color of the control + */ + public function getForeColor() + { + return isset($this->_fields['color'])?$this->_fields['color']:''; + } + + /** + * @param string the foreground color of the control + */ + public function setForeColor($value) + { + if(trim($value)==='') + unset($this->_fields['color']); + else + $this->_fields['color']=$value; + } + + /** + * @return string the height of the control + */ + public function getHeight() + { + return isset($this->_fields['height'])?$this->_fields['height']:''; + } + + /** + * @param string the height of the control + */ + public function setHeight($value) + { + if(trim($value)==='') + unset($this->_fields['height']); + else + $this->_fields['height']=$value; + } + + /** + * @return string the custom style of the control + */ + public function getCustomStyle() + { + return $this->_customStyle===null?'':$this->_customStyle; + } + + /** + * Sets custom style fields from a string. + * Custom style fields will be overwritten by style fields explicitly defined. + * @param string the custom style of the control + */ + public function setCustomStyle($value) + { + $this->_customStyle=$value; + } + + /** + * @return string a single style field value set via {@link setStyleField}. Defaults to empty string. + */ + public function getStyleField($name) + { + return isset($this->_fields[$name])?$this->_fields[$name]:''; + } + + /** + * Sets a single style field value. + * Style fields set by this method will overwrite those set by {@link setCustomStyle}. + * @param string style field name + * @param string style field value + */ + public function setStyleField($name,$value) + { + $this->_fields[$name]=$value; + } + + /** + * Clears a single style field value; + * @param string style field name + */ + public function clearStyleField($name) + { + unset($this->_fields[$name]); + } + + /** + * @return boolean whether a style field has been defined by {@link setStyleField} + */ + public function hasStyleField($name) + { + return isset($this->_fields[$name]); + } + + /** + * @return string the width of the control + */ + public function getWidth() + { + return isset($this->_fields['width'])?$this->_fields['width']:''; + } + + /** + * @param string the width of the control + */ + public function setWidth($value) + { + $this->_fields['width']=$value; + } + + /** + * Resets the style to the original empty state. + */ + public function reset() + { + $this->_fields=array(); + $this->_font=null; + $this->_class=null; + $this->_customStyle=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + if($style instanceof TStyle) + { + $this->_fields=array_merge($this->_fields,$style->_fields); + if($style->_class!==null) + $this->_class=$style->_class; + if($style->_customStyle!==null) + $this->_customStyle=$style->_customStyle; + if($style->_font!==null) + $this->getFont()->copyFrom($style->_font); + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + if($style instanceof TStyle) + { + $this->_fields=array_merge($style->_fields,$this->_fields); + if($this->_class===null) + $this->_class=$style->_class; + if($this->_customStyle===null) + $this->_customStyle=$style->_customStyle; + if($style->_font!==null) + $this->getFont()->mergeWith($style->_font); + } + } + + /** + * Adds attributes related to CSS styles to renderer. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if($this->_customStyle!==null) + { + foreach(explode(';',$this->_customStyle) as $style) + { + $arr=explode(':',$style,2); + if(isset($arr[1]) && trim($arr[0])!=='') + $writer->addStyleAttribute(trim($arr[0]),trim($arr[1])); + } + } + $writer->addStyleAttributes($this->_fields); + if($this->_font!==null) + $this->_font->addAttributesToRender($writer); + if($this->_class!==null) + $writer->addAttribute('class',$this->_class); + } + + /** + * @return array list of style fields. + */ + public function getStyleFields() + { + return $this->_fields; + } +} + +/** + * TDisplayStyle defines the enumerable type for the possible styles + * that a web control can display. + * + * The following enumerable values are defined: + * - None: the control is not displayed and not included in the layout. + * - Dynamic: the control is displayed and included in the layout, the layout flow is dependent on the control (equivalent to display:'' in css). + * - Fixed: Similar to Dynamic with CSS "visibility" set "shown". + * - Hidden: the control is not displayed and is included in the layout. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.1 + */ +class TDisplayStyle extends TEnumerable +{ + const None='None'; + const Dynamic='Dynamic'; + const Fixed='Fixed'; + const Hidden='Hidden'; +} + +/** + * TTableStyle class. + * TTableStyle represents the CSS style specific for HTML table. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableStyle extends TStyle +{ + /** + * @var TVerticalAlign the URL of the background image for the table + */ + private $_backImageUrl=null; + /** + * @var THorizontalAlign horizontal alignment of the contents within the table + */ + private $_horizontalAlign=null; + /** + * @var integer cellpadding of the table + */ + private $_cellPadding=null; + /** + * @var integer cellspacing of the table + */ + private $_cellSpacing=null; + /** + * @var TTableGridLines grid line setting of the table + */ + private $_gridLines=null; + /** + * @var boolean whether the table border should be collapsed + */ + private $_borderCollapse=null; + + /** + * Sets the style attributes to default values. + * This method overrides the parent implementation by + * resetting additional TTableStyle specific attributes. + */ + public function reset() + { + $this->_backImageUrl=null; + $this->_horizontalAlign=null; + $this->_cellPadding=null; + $this->_cellSpacing=null; + $this->_gridLines=null; + $this->_borderCollapse=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TTableStyle) + { + if($style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($style->_cellPadding!==null) + $this->_cellPadding=$style->_cellPadding; + if($style->_cellSpacing!==null) + $this->_cellSpacing=$style->_cellSpacing; + if($style->_gridLines!==null) + $this->_gridLines=$style->_gridLines; + if($style->_borderCollapse!==null) + $this->_borderCollapse=$style->_borderCollapse; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TTableStyle) + { + if($this->_backImageUrl===null && $style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($this->_cellPadding===null && $style->_cellPadding!==null) + $this->_cellPadding=$style->_cellPadding; + if($this->_cellSpacing===null && $style->_cellSpacing!==null) + $this->_cellSpacing=$style->_cellSpacing; + if($this->_gridLines===null && $style->_gridLines!==null) + $this->_gridLines=$style->_gridLines; + if($this->_borderCollapse===null && $style->_borderCollapse!==null) + $this->_borderCollapse=$style->_borderCollapse; + } + } + + + /** + * Adds attributes related to CSS styles to renderer. + * This method overrides the parent implementation. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if(($url=trim($this->getBackImageUrl()))!=='') + $writer->addStyleAttribute('background-image','url('.$url.')'); + + if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) + $writer->addStyleAttribute('text-align',strtolower($horizontalAlign)); + + if(($cellPadding=$this->getCellPadding())>=0) + $writer->addAttribute('cellpadding',"$cellPadding"); + + if(($cellSpacing=$this->getCellSpacing())>=0) + $writer->addAttribute('cellspacing',"$cellSpacing"); + + if($this->getBorderCollapse()) + $writer->addStyleAttribute('border-collapse','collapse'); + + switch($this->getGridLines()) + { + case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break; + case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break; + case TTableGridLines::Both : $writer->addAttribute('rules','all'); break; + } + + parent::addAttributesToRender($writer); + } + + /** + * @return string the URL of the background image for the table + */ + public function getBackImageUrl() + { + return $this->_backImageUrl===null?'':$this->_backImageUrl; + } + + /** + * Sets the URL of the background image for the table + * @param string the URL + */ + public function setBackImageUrl($value) + { + $this->_backImageUrl=$value; + } + + /** + * @return THorizontalAlign the horizontal alignment of the contents within the table, defaults to THorizontalAlign::NotSet. + */ + public function getHorizontalAlign() + { + return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; + } + + /** + * Sets the horizontal alignment of the contents within the table. + * @param THorizontalAlign the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); + } + + /** + * @return integer cellpadding of the table. Defaults to -1, meaning not set. + */ + public function getCellPadding() + { + return $this->_cellPadding===null?-1:$this->_cellPadding; + } + + /** + * @param integer cellpadding of the table. A value equal to -1 clears up the setting. + * @throws TInvalidDataValueException if the value is less than -1. + */ + public function setCellPadding($value) + { + if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1) + throw new TInvalidDataValueException('tablestyle_cellpadding_invalid'); + } + + /** + * @return integer cellspacing of the table. Defaults to -1, meaning not set. + */ + public function getCellSpacing() + { + return $this->_cellSpacing===null?-1:$this->_cellSpacing; + } + + /** + * @param integer cellspacing of the table. A value equal to -1 clears up the setting. + * @throws TInvalidDataValueException if the value is less than -1. + */ + public function setCellSpacing($value) + { + if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1) + throw new TInvalidDataValueException('tablestyle_cellspacing_invalid'); + } + + /** + * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None. + */ + public function getGridLines() + { + return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines; + } + + /** + * Sets the grid line style of the table. + * @param TTableGridLines the grid line setting of the table + */ + public function setGridLines($value) + { + $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines'); + } + + + /** + * @return boolean whether the table borders should be collapsed. Defaults to false. + */ + public function getBorderCollapse() + { + return $this->_borderCollapse===null?false:$this->_borderCollapse; + } + + /** + * @param boolean whether the table borders should be collapsed. + */ + public function setBorderCollapse($value) + { + $this->_borderCollapse=TPropertyValue::ensureBoolean($value); + } +} + +/** + * TTableItemStyle class. + * TTableItemStyle represents the CSS style specific for HTML table item. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableItemStyle extends TStyle +{ + /** + * @var THorizontalAlign horizontal alignment of the contents within the table item + */ + private $_horizontalAlign=null; + /** + * @var TVerticalAlign vertical alignment of the contents within the table item + */ + private $_verticalAlign=null; + /** + * @var boolean whether the content wraps within the table item + */ + private $_wrap=null; + + /** + * Sets the style attributes to default values. + * This method overrides the parent implementation by + * resetting additional TTableItemStyle specific attributes. + */ + public function reset() + { + parent::reset(); + $this->_verticalAlign=null; + $this->_horizontalAlign=null; + $this->_wrap=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TTableItemStyle) + { + if($this->_verticalAlign===null && $style->_verticalAlign!==null) + $this->_verticalAlign=$style->_verticalAlign; + if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($this->_wrap===null && $style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TTableItemStyle) + { + if($style->_verticalAlign!==null) + $this->_verticalAlign=$style->_verticalAlign; + if($style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } + + /** + * Adds attributes related to CSS styles to renderer. + * This method overrides the parent implementation. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer) + { + if(!$this->getWrap()) + $writer->addStyleAttribute('white-space','nowrap'); + + if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) + $writer->addAttribute('align',strtolower($horizontalAlign)); + + if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet) + $writer->addAttribute('valign',strtolower($verticalAlign)); + + parent::addAttributesToRender($writer); + } + + /** + * @return THorizontalAlign the horizontal alignment of the contents within the table item, defaults to THorizontalAlign::NotSet. + */ + public function getHorizontalAlign() + { + return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; + } + + /** + * Sets the horizontal alignment of the contents within the table item. + * @param THorizontalAlign the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); + } + + /** + * @return TVerticalAlign the vertical alignment of the contents within the table item, defaults to TVerticalAlign::NotSet. + */ + public function getVerticalAlign() + { + return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign; + } + + /** + * Sets the vertical alignment of the contents within the table item. + * @param TVerticalAlign the horizontal alignment + */ + public function setVerticalAlign($value) + { + $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign'); + } + + /** + * @return boolean whether the content wraps within the table item. Defaults to true. + */ + public function getWrap() + { + return $this->_wrap===null?true:$this->_wrap; + } + + /** + * Sets the value indicating whether the content wraps within the table item. + * @param boolean whether the content wraps within the panel. + */ + public function setWrap($value) + { + $this->_wrap=TPropertyValue::ensureBoolean($value); + } +} + +/** + * THorizontalAlign class. + * THorizontalAlign defines the enumerable type for the possible horizontal alignments in a CSS style. + * + * The following enumerable values are defined: + * - NotSet: the alignment is not specified. + * - Left: left aligned + * - Right: right aligned + * - Center: center aligned + * - Justify: the begin and end are justified + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class THorizontalAlign extends TEnumerable +{ + const NotSet='NotSet'; + const Left='Left'; + const Right='Right'; + const Center='Center'; + const Justify='Justify'; +} + +/** + * TVerticalAlign class. + * TVerticalAlign defines the enumerable type for the possible vertical alignments in a CSS style. + * + * The following enumerable values are defined: + * - NotSet: the alignment is not specified. + * - Top: top aligned + * - Bottom: bottom aligned + * - Middle: middle aligned + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TVerticalAlign extends TEnumerable +{ + const NotSet='NotSet'; + const Top='Top'; + const Bottom='Bottom'; + const Middle='Middle'; +} + + +/** + * TTableGridLines class. + * TTableGridLines defines the enumerable type for the possible grid line types of an HTML table. + * + * The following enumerable values are defined: + * - None: no grid lines + * - Horizontal: horizontal grid lines only + * - Vertical: vertical grid lines only + * - Both: both horizontal and vertical grid lines are shown + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTableGridLines extends TEnumerable +{ + const None='None'; + const Horizontal='Horizontal'; + const Vertical='Vertical'; + const Both='Both'; +} + diff --git a/framework/Web/UI/WebControls/TTable.php b/framework/Web/UI/WebControls/TTable.php index a333bf09..b7a774ae 100644 --- a/framework/Web/UI/WebControls/TTable.php +++ b/framework/Web/UI/WebControls/TTable.php @@ -1,410 +1,410 @@ -<?php
-/**
- * TTable and TTableRowCollection class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTable and TTableRowCollection class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTable class
- *
- * TTable displays an HTML table on a Web page.
- *
- * A table may have {@link setCaption Caption}, whose alignment is specified
- * via {@link setCaptionAlign CaptionAlign}. The table cellpadding and cellspacing
- * are specified via {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
- * properties, respectively. The {@link setGridLines GridLines} specifies how
- * the table should display its borders. The horizontal alignment of the table
- * content can be specified via {@link setHorizontalAlign HorizontalAlign},
- * and {@link setBackImageUrl BackImageUrl} can assign a background image to the table.
- *
- * A TTable maintains a list of {@link TTableRow} controls in its
- * {@link getRows Rows} property. Each {@link TTableRow} represents
- * an HTML table row.
- *
- * To populate the table {@link getRows Rows}, you may either use control template
- * or dynamically create {@link TTableRow} in code.
- * In template, do as follows to create the table rows and cells,
- * <code>
- * <com:TTable>
- * <com:TTableRow>
- * <com:TTableCell Text="content" />
- * <com:TTableCell Text="content" />
- * </com:TTableRow>
- * <com:TTableRow>
- * <com:TTableCell Text="content" />
- * <com:TTableCell Text="content" />
- * </com:TTableRow>
- * </com:TTable>
- * </code>
- * The above can also be accomplished in code as follows,
- * <code>
- * $table=new TTable;
- * $row=new TTableRow;
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $table->Rows->add($row);
- * $row=new TTableRow;
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $table->Rows->add($row);
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTable extends TWebControl
-{
- /**
- * @return string tag name for the table
- */
- protected function getTagName()
- {
- return 'table';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TTableRow} objects into the {@link getRows Rows} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TTableRow)
- $this->getRows()->add($object);
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by the table.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $border=0;
- if($this->getHasStyle())
- {
- if($this->getGridLines()!==TTableGridLines::None)
- {
- if(($border=$this->getBorderWidth())==='')
- $border=1;
- else
- $border=(int)$border;
- }
- }
- $writer->addAttribute('border',"$border");
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TTableRowCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return new TTableRowCollection($this);
- }
-
- /**
- * @return TTableRowCollection list of {@link TTableRow} controls
- */
- public function getRows()
- {
- return $this->getControls();
- }
-
- /**
- * @return string table caption
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string table caption
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',$value,'');
- }
-
- /**
- * @return TTableCaptionAlign table caption alignment. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
- }
-
- /**
- * @param TTableCaptionAlign table caption alignment.
- */
- public function setCaptionAlign($value)
- {
- $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
- }
-
- /**
- * @return integer the cellspacing for the table. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * @param integer the cellspacing for the table. Defaults to -1, meaning not set.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * @param integer the cellpadding for the table. Defaults to -1, meaning not set.
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return THorizontalAlign::NotSet;
- }
-
- /**
- * @param THorizontalAlign the horizontal alignment of the table content.
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getGridLines();
- else
- return TTableGridLines::None;
- }
-
- /**
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->getStyle()->setGridLines($value);
- }
-
- /**
- * @return string the URL of the background image for the table
- */
- public function getBackImageUrl()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getBackImageUrl();
- else
- return '';
- }
-
- /**
- * Sets the URL of the background image for the table
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * Renders the openning tag for the table control which will render table caption if present.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($caption=$this->getCaption())!=='')
- {
- if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
- $writer->addAttribute('align',strtolower($align));
- $writer->renderBeginTag('caption');
- $writer->write($caption);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders body contents of the table.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if($this->getHasControls())
- {
- $renderTableSection=false;
- foreach($this->getControls() as $row)
- {
- if($row->getTableSection()!==TTableRowSection::Body)
- {
- $renderTableSection=true;
- break;
- }
- }
- if($renderTableSection)
- {
- $currentSection=TTableRowSection::Header;
- $writer->writeLine();
- foreach($this->getControls() as $index=>$row)
- {
- if(($section=$row->getTableSection())===$currentSection)
- {
- if($index===0 && $currentSection===TTableRowSection::Header)
- $writer->renderBeginTag('thead');
- }
- else
- {
- if($currentSection===TTableRowSection::Header)
- {
- if($index>0)
- $writer->renderEndTag();
- if($section===TTableRowSection::Body)
- $writer->renderBeginTag('tbody');
- else
- $writer->renderBeginTag('tfoot');
- $currentSection=$section;
- }
- else if($currentSection===TTableRowSection::Body)
- {
- $writer->renderEndTag();
- if($section===TTableRowSection::Footer)
- $writer->renderBeginTag('tfoot');
- else
- throw new TConfigurationException('table_tablesection_outoforder');
- $currentSection=$section;
- }
- else // Footer
- throw new TConfigurationException('table_tablesection_outoforder');
- }
- $row->renderControl($writer);
- $writer->writeLine();
- }
- $writer->renderEndTag();
- }
- else
- {
- $writer->writeLine();
- foreach($this->getControls() as $row)
- {
- $row->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
- }
-}
-
-
-/**
- * TTableRowCollection class.
- *
- * TTableRowCollection is used to maintain a list of rows belong to a table.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableRowCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added table row.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TTableRow object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TTableRow)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tablerowcollection_tablerow_required');
- }
-}
-
-
-/**
- * TTableCaptionAlign class.
- * TTableCaptionAlign defines the enumerable type for the possible alignments
- * that a table caption can take.
- *
- * The following enumerable values are defined:
- * - NotSet: alignment not specified
- * - Top: top aligned
- * - Bottom: bottom aligned
- * - Left: left aligned
- * - Right: right aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableCaptionAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Top='Top';
- const Bottom='Bottom';
- const Left='Left';
- const Right='Right';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTableRow class + */ +Prado::using('System.Web.UI.WebControls.TTableRow'); + +/** + * TTable class + * + * TTable displays an HTML table on a Web page. + * + * A table may have {@link setCaption Caption}, whose alignment is specified + * via {@link setCaptionAlign CaptionAlign}. The table cellpadding and cellspacing + * are specified via {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing} + * properties, respectively. The {@link setGridLines GridLines} specifies how + * the table should display its borders. The horizontal alignment of the table + * content can be specified via {@link setHorizontalAlign HorizontalAlign}, + * and {@link setBackImageUrl BackImageUrl} can assign a background image to the table. + * + * A TTable maintains a list of {@link TTableRow} controls in its + * {@link getRows Rows} property. Each {@link TTableRow} represents + * an HTML table row. + * + * To populate the table {@link getRows Rows}, you may either use control template + * or dynamically create {@link TTableRow} in code. + * In template, do as follows to create the table rows and cells, + * <code> + * <com:TTable> + * <com:TTableRow> + * <com:TTableCell Text="content" /> + * <com:TTableCell Text="content" /> + * </com:TTableRow> + * <com:TTableRow> + * <com:TTableCell Text="content" /> + * <com:TTableCell Text="content" /> + * </com:TTableRow> + * </com:TTable> + * </code> + * The above can also be accomplished in code as follows, + * <code> + * $table=new TTable; + * $row=new TTableRow; + * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell); + * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell); + * $table->Rows->add($row); + * $row=new TTableRow; + * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell); + * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell); + * $table->Rows->add($row); + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTable extends TWebControl +{ + /** + * @return string tag name for the table + */ + protected function getTagName() + { + return 'table'; + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TTableRow} objects into the {@link getRows Rows} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + if($object instanceof TTableRow) + $this->getRows()->add($object); + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableStyle} to be used by the table. + * @return TTableStyle control style to be used + */ + protected function createStyle() + { + return new TTableStyle; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $border=0; + if($this->getHasStyle()) + { + if($this->getGridLines()!==TTableGridLines::None) + { + if(($border=$this->getBorderWidth())==='') + $border=1; + else + $border=(int)$border; + } + } + $writer->addAttribute('border',"$border"); + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TTableRowCollection control collection + * @see getControls + */ + protected function createControlCollection() + { + return new TTableRowCollection($this); + } + + /** + * @return TTableRowCollection list of {@link TTableRow} controls + */ + public function getRows() + { + return $this->getControls(); + } + + /** + * @return string table caption + */ + public function getCaption() + { + return $this->getViewState('Caption',''); + } + + /** + * @param string table caption + */ + public function setCaption($value) + { + $this->setViewState('Caption',$value,''); + } + + /** + * @return TTableCaptionAlign table caption alignment. Defaults to TTableCaptionAlign::NotSet. + */ + public function getCaptionAlign() + { + return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet); + } + + /** + * @param TTableCaptionAlign table caption alignment. + */ + public function setCaptionAlign($value) + { + $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet); + } + + /** + * @return integer the cellspacing for the table. Defaults to -1, meaning not set. + */ + public function getCellSpacing() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellSpacing(); + else + return -1; + } + + /** + * @param integer the cellspacing for the table. Defaults to -1, meaning not set. + */ + public function setCellSpacing($value) + { + $this->getStyle()->setCellSpacing($value); + } + + /** + * @return integer the cellpadding for the table. Defaults to -1, meaning not set. + */ + public function getCellPadding() + { + if($this->getHasStyle()) + return $this->getStyle()->getCellPadding(); + else + return -1; + } + + /** + * @param integer the cellpadding for the table. Defaults to -1, meaning not set. + */ + public function setCellPadding($value) + { + $this->getStyle()->setCellPadding($value); + } + + /** + * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet. + */ + public function getHorizontalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getHorizontalAlign(); + else + return THorizontalAlign::NotSet; + } + + /** + * @param THorizontalAlign the horizontal alignment of the table content. + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None. + */ + public function getGridLines() + { + if($this->getHasStyle()) + return $this->getStyle()->getGridLines(); + else + return TTableGridLines::None; + } + + /** + * @param TTableGridLines the grid line setting of the table + */ + public function setGridLines($value) + { + $this->getStyle()->setGridLines($value); + } + + /** + * @return string the URL of the background image for the table + */ + public function getBackImageUrl() + { + if($this->getHasStyle()) + return $this->getStyle()->getBackImageUrl(); + else + return ''; + } + + /** + * Sets the URL of the background image for the table + * @param string the URL + */ + public function setBackImageUrl($value) + { + $this->getStyle()->setBackImageUrl($value); + } + + /** + * Renders the openning tag for the table control which will render table caption if present. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function renderBeginTag($writer) + { + parent::renderBeginTag($writer); + if(($caption=$this->getCaption())!=='') + { + if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet) + $writer->addAttribute('align',strtolower($align)); + $writer->renderBeginTag('caption'); + $writer->write($caption); + $writer->renderEndTag(); + } + } + + /** + * Renders body contents of the table. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + if($this->getHasControls()) + { + $renderTableSection=false; + foreach($this->getControls() as $row) + { + if($row->getTableSection()!==TTableRowSection::Body) + { + $renderTableSection=true; + break; + } + } + if($renderTableSection) + { + $currentSection=TTableRowSection::Header; + $writer->writeLine(); + foreach($this->getControls() as $index=>$row) + { + if(($section=$row->getTableSection())===$currentSection) + { + if($index===0 && $currentSection===TTableRowSection::Header) + $writer->renderBeginTag('thead'); + } + else + { + if($currentSection===TTableRowSection::Header) + { + if($index>0) + $writer->renderEndTag(); + if($section===TTableRowSection::Body) + $writer->renderBeginTag('tbody'); + else + $writer->renderBeginTag('tfoot'); + $currentSection=$section; + } + else if($currentSection===TTableRowSection::Body) + { + $writer->renderEndTag(); + if($section===TTableRowSection::Footer) + $writer->renderBeginTag('tfoot'); + else + throw new TConfigurationException('table_tablesection_outoforder'); + $currentSection=$section; + } + else // Footer + throw new TConfigurationException('table_tablesection_outoforder'); + } + $row->renderControl($writer); + $writer->writeLine(); + } + $writer->renderEndTag(); + } + else + { + $writer->writeLine(); + foreach($this->getControls() as $row) + { + $row->renderControl($writer); + $writer->writeLine(); + } + } + } + } +} + + +/** + * TTableRowCollection class. + * + * TTableRowCollection is used to maintain a list of rows belong to a table. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableRowCollection extends TControlCollection +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing additional + * operations for each newly added table row. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TTableRow object. + */ + public function insertAt($index,$item) + { + if($item instanceof TTableRow) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('tablerowcollection_tablerow_required'); + } +} + + +/** + * TTableCaptionAlign class. + * TTableCaptionAlign defines the enumerable type for the possible alignments + * that a table caption can take. + * + * The following enumerable values are defined: + * - NotSet: alignment not specified + * - Top: top aligned + * - Bottom: bottom aligned + * - Left: left aligned + * - Right: right aligned + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTableCaptionAlign extends TEnumerable +{ + const NotSet='NotSet'; + const Top='Top'; + const Bottom='Bottom'; + const Left='Left'; + const Right='Right'; +} + diff --git a/framework/Web/UI/WebControls/TTableCell.php b/framework/Web/UI/WebControls/TTableCell.php index 6b43990b..70ff573f 100644 --- a/framework/Web/UI/WebControls/TTableCell.php +++ b/framework/Web/UI/WebControls/TTableCell.php @@ -1,222 +1,222 @@ -<?php
-/**
- * TTableCell class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTableCell class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTableCell class.
- *
- * TTableCell displays a table cell on a Web page. Content of the table cell
- * is specified by the {@link setText Text} property. If {@link setText Text}
- * is empty, the body contents enclosed by the table cell component tag are rendered.
- * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure
- * it does not contain dangerous characters.
- *
- * The horizontal and vertical alignments of the contents in the cell
- * are specified via {@link setHorizontalAlign HorizontalAlign} and
- * {@link setVerticalAlign VerticalAlign} properties, respectively.
- *
- * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan}
- * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property
- * indicates whether the contents in the cell should be wrapped.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableCell extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name for the table cell
- */
- protected function getTagName()
- {
- return 'td';
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by the table cell.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getVerticalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getVerticalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * Valid values include 'NotSet','Top','Bottom','Middle'
- * @param string the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->getStyle()->setVerticalAlign($value);
- }
-
- /**
- * @return integer the columnspan for the table cell, 0 if not set.
- */
- public function getColumnSpan()
- {
- return $this->getViewState('ColumnSpan', 0);
- }
-
- /**
- * Sets the columnspan for the table cell.
- * @param integer the columnspan for the table cell, 0 if not set.
- */
- public function setColumnSpan($value)
- {
- $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0);
- }
-
- /**
- * @return integer the rowspan for the table cell, 0 if not set.
- */
- public function getRowSpan()
- {
- return $this->getViewState('RowSpan', 0);
- }
-
- /**
- * Sets the rowspan for the table cell.
- * @param integer the rowspan for the table cell, 0 if not set.
- */
- public function setRowSpan($value)
- {
- $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0);
- }
-
- /**
- * @return boolean whether the text content wraps within a table cell. Defaults to true.
- */
- public function getWrap()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getWrap();
- else
- return true;
- }
-
- /**
- * Sets the value indicating whether the text content wraps within a table cell.
- * @param boolean whether the text content wraps within a table cell.
- */
- public function setWrap($value)
- {
- $this->getStyle()->setWrap($value);
- }
-
- /**
- * @return string the text content of the table cell.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content of the table cell.
- * If the text content is empty, body content (child controls) of the cell will be rendered.
- * @param string the text content
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the text content of the table cell.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text content of the table cell.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text content of the table cell.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text content of the table cell.
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($colspan=$this->getColumnSpan())>0)
- $writer->addAttribute('colspan',"$colspan");
- if(($rowspan=$this->getRowSpan())>0)
- $writer->addAttribute('rowspan',"$rowspan");
- }
-
- /**
- * Renders body contents of the table cell.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())!=='')
- $writer->write($text);
- else if($this->getHasControls())
- parent::renderContents($writer);
- else
- $writer->write(' ');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TTableCell class. + * + * TTableCell displays a table cell on a Web page. Content of the table cell + * is specified by the {@link setText Text} property. If {@link setText Text} + * is empty, the body contents enclosed by the table cell component tag are rendered. + * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure + * it does not contain dangerous characters. + * + * The horizontal and vertical alignments of the contents in the cell + * are specified via {@link setHorizontalAlign HorizontalAlign} and + * {@link setVerticalAlign VerticalAlign} properties, respectively. + * + * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan} + * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property + * indicates whether the contents in the cell should be wrapped. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableCell extends TWebControl implements IDataRenderer +{ + /** + * @return string tag name for the table cell + */ + protected function getTagName() + { + return 'td'; + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableItemStyle} to be used by the table cell. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getHorizontalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getHorizontalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the horizontal alignment of the contents within the table item. + * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center' + * @param string the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getVerticalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getVerticalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the vertical alignment of the contents within the table item. + * Valid values include 'NotSet','Top','Bottom','Middle' + * @param string the horizontal alignment + */ + public function setVerticalAlign($value) + { + $this->getStyle()->setVerticalAlign($value); + } + + /** + * @return integer the columnspan for the table cell, 0 if not set. + */ + public function getColumnSpan() + { + return $this->getViewState('ColumnSpan', 0); + } + + /** + * Sets the columnspan for the table cell. + * @param integer the columnspan for the table cell, 0 if not set. + */ + public function setColumnSpan($value) + { + $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0); + } + + /** + * @return integer the rowspan for the table cell, 0 if not set. + */ + public function getRowSpan() + { + return $this->getViewState('RowSpan', 0); + } + + /** + * Sets the rowspan for the table cell. + * @param integer the rowspan for the table cell, 0 if not set. + */ + public function setRowSpan($value) + { + $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0); + } + + /** + * @return boolean whether the text content wraps within a table cell. Defaults to true. + */ + public function getWrap() + { + if($this->getHasStyle()) + return $this->getStyle()->getWrap(); + else + return true; + } + + /** + * Sets the value indicating whether the text content wraps within a table cell. + * @param boolean whether the text content wraps within a table cell. + */ + public function setWrap($value) + { + $this->getStyle()->setWrap($value); + } + + /** + * @return string the text content of the table cell. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text content of the table cell. + * If the text content is empty, body content (child controls) of the cell will be rendered. + * @param string the text content + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + } + + /** + * Returns the text content of the table cell. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text content of the table cell. + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the text content of the table cell. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text content of the table cell. + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if(($colspan=$this->getColumnSpan())>0) + $writer->addAttribute('colspan',"$colspan"); + if(($rowspan=$this->getRowSpan())>0) + $writer->addAttribute('rowspan',"$rowspan"); + } + + /** + * Renders body contents of the table cell. + * @param THtmlWriter the writer used for the rendering purpose. + */ + public function renderContents($writer) + { + if(($text=$this->getText())!=='') + $writer->write($text); + else if($this->getHasControls()) + parent::renderContents($writer); + else + $writer->write(' '); + } +} + diff --git a/framework/Web/UI/WebControls/TTableFooterRow.php b/framework/Web/UI/WebControls/TTableFooterRow.php index 84bc29f1..1387c385 100644 --- a/framework/Web/UI/WebControls/TTableFooterRow.php +++ b/framework/Web/UI/WebControls/TTableFooterRow.php @@ -1,47 +1,47 @@ -<?php
-/**
- * TTableFooterRow class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTableFooterRow class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class.
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTableFooterRow class.
- *
- * TTableFooterRow displays a table footer row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TTableFooterRow extends TTableRow
-{
- /**
- * @return string location of a row in a table. Always returns 'Footer'.
- */
- public function getTableSection()
- {
- return 'Footer';
- }
-
- /**
- * @param string location of a row in a table.
- * @throws TInvalidOperationException if this method is invoked
- */
- public function setTableSection($value)
- {
- throw new TInvalidOperationException('tablefooterrow_tablesection_readonly');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTableRow class. + */ +Prado::using('System.Web.UI.WebControls.TTableRow'); + +/** + * TTableFooterRow class. + * + * TTableFooterRow displays a table footer row. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.1 + */ +class TTableFooterRow extends TTableRow +{ + /** + * @return string location of a row in a table. Always returns 'Footer'. + */ + public function getTableSection() + { + return 'Footer'; + } + + /** + * @param string location of a row in a table. + * @throws TInvalidOperationException if this method is invoked + */ + public function setTableSection($value) + { + throw new TInvalidOperationException('tablefooterrow_tablesection_readonly'); + } +} + diff --git a/framework/Web/UI/WebControls/TTableHeaderCell.php b/framework/Web/UI/WebControls/TTableHeaderCell.php index bbf3e58a..72eae44e 100644 --- a/framework/Web/UI/WebControls/TTableHeaderCell.php +++ b/framework/Web/UI/WebControls/TTableHeaderCell.php @@ -1,124 +1,124 @@ -<?php
-/**
- * TTableHeaderCell class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTableHeaderCell class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableCell class
- */
-Prado::using('System.Web.UI.WebControls.TTableCell');
-
-
-/**
- * TTableHeaderCell class.
- *
- * TTableHeaderCell displays a table header cell on a Web page.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableHeaderCell extends TTableCell
-{
- /**
- * @return string tag name for the table header cell
- */
- protected function getTagName()
- {
- return 'th';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($scope=$this->getScope())!==TTableHeaderScope::NotSet)
- $writer->addAttribute('scope',$scope===TTableHeaderScope::Row?'row':'col');
- if(($text=$this->getAbbreviatedText())!=='')
- $writer->addAttribute('abbr',$text);
- if(($text=$this->getCategoryText())!=='')
- $writer->addAttribute('axis',$text);
- }
-
- /**
- * @return TTableHeaderScope the scope of the cells that the header cell applies to. Defaults to TTableHeaderScope::NotSet.
- */
- public function getScope()
- {
- return $this->getViewState('Scope',TTableHeaderScope::NotSet);
- }
-
- /**
- * @param TTableHeaderScope the scope of the cells that the header cell applies to.
- */
- public function setScope($value)
- {
- $this->setViewState('Scope',TPropertyValue::ensureEnum($value,'TTableHeaderScope'),TTableHeaderScope::NotSet);
- }
-
- /**
- * @return string the abbr attribute of the HTML th element
- */
- public function getAbbreviatedText()
- {
- return $this->getViewState('AbbreviatedText','');
- }
-
- /**
- * @param string the abbr attribute of the HTML th element
- */
- public function setAbbreviatedText($value)
- {
- $this->setViewState('AbbreviatedText',$value,'');
- }
-
- /**
- * @return string the axis attribute of the HTML th element
- */
- public function getCategoryText()
- {
- return $this->getViewState('CategoryText','');
- }
-
- /**
- * @param string the axis attribute of the HTML th element
- */
- public function setCategoryText($value)
- {
- $this->setViewState('CategoryText',$value,'');
- }
-}
-
-
-/**
- * TTableHeaderScope class.
- * TTableHeaderScope defines the enumerable type for the possible table scopes that a table header is associated with.
- *
- * The following enumerable values are defined:
- * - NotSet: the scope is not specified
- * - Row: the scope is row-wise
- * - Column: the scope is column-wise
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableHeaderScope extends TEnumerable
-{
- const NotSet='NotSet';
- const Row='Row';
- const Column='Column';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTableCell class + */ +Prado::using('System.Web.UI.WebControls.TTableCell'); + + +/** + * TTableHeaderCell class. + * + * TTableHeaderCell displays a table header cell on a Web page. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableHeaderCell extends TTableCell +{ + /** + * @return string tag name for the table header cell + */ + protected function getTagName() + { + return 'th'; + } + + /** + * Adds attributes to renderer. + * @param THtmlWriter the renderer + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if(($scope=$this->getScope())!==TTableHeaderScope::NotSet) + $writer->addAttribute('scope',$scope===TTableHeaderScope::Row?'row':'col'); + if(($text=$this->getAbbreviatedText())!=='') + $writer->addAttribute('abbr',$text); + if(($text=$this->getCategoryText())!=='') + $writer->addAttribute('axis',$text); + } + + /** + * @return TTableHeaderScope the scope of the cells that the header cell applies to. Defaults to TTableHeaderScope::NotSet. + */ + public function getScope() + { + return $this->getViewState('Scope',TTableHeaderScope::NotSet); + } + + /** + * @param TTableHeaderScope the scope of the cells that the header cell applies to. + */ + public function setScope($value) + { + $this->setViewState('Scope',TPropertyValue::ensureEnum($value,'TTableHeaderScope'),TTableHeaderScope::NotSet); + } + + /** + * @return string the abbr attribute of the HTML th element + */ + public function getAbbreviatedText() + { + return $this->getViewState('AbbreviatedText',''); + } + + /** + * @param string the abbr attribute of the HTML th element + */ + public function setAbbreviatedText($value) + { + $this->setViewState('AbbreviatedText',$value,''); + } + + /** + * @return string the axis attribute of the HTML th element + */ + public function getCategoryText() + { + return $this->getViewState('CategoryText',''); + } + + /** + * @param string the axis attribute of the HTML th element + */ + public function setCategoryText($value) + { + $this->setViewState('CategoryText',$value,''); + } +} + + +/** + * TTableHeaderScope class. + * TTableHeaderScope defines the enumerable type for the possible table scopes that a table header is associated with. + * + * The following enumerable values are defined: + * - NotSet: the scope is not specified + * - Row: the scope is row-wise + * - Column: the scope is column-wise + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTableHeaderScope extends TEnumerable +{ + const NotSet='NotSet'; + const Row='Row'; + const Column='Column'; +} + diff --git a/framework/Web/UI/WebControls/TTableHeaderRow.php b/framework/Web/UI/WebControls/TTableHeaderRow.php index 448902dc..2c05b94d 100644 --- a/framework/Web/UI/WebControls/TTableHeaderRow.php +++ b/framework/Web/UI/WebControls/TTableHeaderRow.php @@ -1,47 +1,47 @@ -<?php
-/**
- * TTableHeaderRow class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTableHeaderRow class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class.
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTableHeaderRow class.
- *
- * TTableHeaderRow displays a table header row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TTableHeaderRow extends TTableRow
-{
- /**
- * @return string location of a row in a table. Always returns 'Header'.
- */
- public function getTableSection()
- {
- return 'Header';
- }
-
- /**
- * @param string location of a row in a table.
- * @throws TInvalidOperationException if this method is invoked
- */
- public function setTableSection($value)
- {
- throw new TInvalidOperationException('tableheaderrow_tablesection_readonly');
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTableRow class. + */ +Prado::using('System.Web.UI.WebControls.TTableRow'); + +/** + * TTableHeaderRow class. + * + * TTableHeaderRow displays a table header row. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.1 + */ +class TTableHeaderRow extends TTableRow +{ + /** + * @return string location of a row in a table. Always returns 'Header'. + */ + public function getTableSection() + { + return 'Header'; + } + + /** + * @param string location of a row in a table. + * @throws TInvalidOperationException if this method is invoked + */ + public function setTableSection($value) + { + throw new TInvalidOperationException('tableheaderrow_tablesection_readonly'); + } +} + diff --git a/framework/Web/UI/WebControls/TTableRow.php b/framework/Web/UI/WebControls/TTableRow.php index e50099bf..3cfc82d0 100644 --- a/framework/Web/UI/WebControls/TTableRow.php +++ b/framework/Web/UI/WebControls/TTableRow.php @@ -1,208 +1,208 @@ -<?php
-/**
- * TTableRow and TTableCellCollection class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTableRow and TTableCellCollection class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableCell class
- */
-Prado::using('System.Web.UI.WebControls.TTableCell');
-
-/**
- * TTableRow class.
- *
- * TTableRow displays a table row. The table cells in the row can be accessed
- * via {@link getCells Cells}. The horizontal and vertical alignments of the row
- * are specified via {@link setHorizontalAlign HorizontalAlign} and
- * {@link setVerticalAlign VerticalAlign} properties, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableRow extends TWebControl
-{
- /**
- * @return string tag name for the table
- */
- protected function getTagName()
- {
- return 'tr';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TTableCell} objects into the {@link getCells Cells} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TTableCell)
- $this->getCells()->add($object);
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by the table row.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TTableCellCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return new TTableCellCollection($this);
- }
-
- /**
- * @return TTableCellCollection list of {@link TTableCell} controls
- */
- public function getCells()
- {
- return $this->getControls();
- }
-
- /**
- * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getVerticalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getVerticalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * Valid values include 'NotSet','Top','Bottom','Middle'
- * @param string the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->getStyle()->setVerticalAlign($value);
- }
-
- /**
- * @return TTableRowSection location of a row in a table. Defaults to TTableRowSection::Body.
- */
- public function getTableSection()
- {
- return $this->getViewState('TableSection',TTableRowSection::Body);
- }
-
- /**
- * @param TTableRowSection location of a row in a table.
- */
- public function setTableSection($value)
- {
- $this->setViewState('TableSection',TPropertyValue::ensureEnum($value,'TTableRowSection'),TTableRowSection::Body);
- }
-
- /**
- * Renders body contents of the table row
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderContents($writer)
- {
- if($this->getHasControls())
- {
- $writer->writeLine();
- foreach($this->getControls() as $cell)
- {
- $cell->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
-}
-
-/**
- * TTableCellCollection class.
- *
- * TTableCellCollection is used to maintain a list of cells belong to a table row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableCellCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added table cell.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TTableCell object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TTableCell)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tablecellcollection_tablecell_required');
- }
-}
-
-
-/**
- * TTableRowSection class.
- * TTableRowSection defines the enumerable type for the possible table sections
- * that a {@link TTableRow} can be within.
- *
- * The following enumerable values are defined:
- * - Header: in table header
- * - Body: in table body
- * - Footer: in table footer
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableRowSection extends TEnumerable
-{
- const Header='Header';
- const Body='Body';
- const Footer='Footer';
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TTableCell class + */ +Prado::using('System.Web.UI.WebControls.TTableCell'); + +/** + * TTableRow class. + * + * TTableRow displays a table row. The table cells in the row can be accessed + * via {@link getCells Cells}. The horizontal and vertical alignments of the row + * are specified via {@link setHorizontalAlign HorizontalAlign} and + * {@link setVerticalAlign VerticalAlign} properties, respectively. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableRow extends TWebControl +{ + /** + * @return string tag name for the table + */ + protected function getTagName() + { + return 'tr'; + } + + /** + * Adds object parsed from template to the control. + * This method adds only {@link TTableCell} objects into the {@link getCells Cells} collection. + * All other objects are ignored. + * @param mixed object parsed from template + */ + public function addParsedObject($object) + { + if($object instanceof TTableCell) + $this->getCells()->add($object); + } + + /** + * Creates a style object for the control. + * This method creates a {@link TTableItemStyle} to be used by the table row. + * @return TStyle control style to be used + */ + protected function createStyle() + { + return new TTableItemStyle; + } + + /** + * Creates a control collection object that is to be used to hold child controls + * @return TTableCellCollection control collection + * @see getControls + */ + protected function createControlCollection() + { + return new TTableCellCollection($this); + } + + /** + * @return TTableCellCollection list of {@link TTableCell} controls + */ + public function getCells() + { + return $this->getControls(); + } + + /** + * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getHorizontalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getHorizontalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the horizontal alignment of the contents within the table item. + * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center' + * @param string the horizontal alignment + */ + public function setHorizontalAlign($value) + { + $this->getStyle()->setHorizontalAlign($value); + } + + /** + * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'. + */ + public function getVerticalAlign() + { + if($this->getHasStyle()) + return $this->getStyle()->getVerticalAlign(); + else + return 'NotSet'; + } + + /** + * Sets the vertical alignment of the contents within the table item. + * Valid values include 'NotSet','Top','Bottom','Middle' + * @param string the horizontal alignment + */ + public function setVerticalAlign($value) + { + $this->getStyle()->setVerticalAlign($value); + } + + /** + * @return TTableRowSection location of a row in a table. Defaults to TTableRowSection::Body. + */ + public function getTableSection() + { + return $this->getViewState('TableSection',TTableRowSection::Body); + } + + /** + * @param TTableRowSection location of a row in a table. + */ + public function setTableSection($value) + { + $this->setViewState('TableSection',TPropertyValue::ensureEnum($value,'TTableRowSection'),TTableRowSection::Body); + } + + /** + * Renders body contents of the table row + * @param THtmlWriter writer for the rendering purpose + */ + public function renderContents($writer) + { + if($this->getHasControls()) + { + $writer->writeLine(); + foreach($this->getControls() as $cell) + { + $cell->renderControl($writer); + $writer->writeLine(); + } + } + } +} + +/** + * TTableCellCollection class. + * + * TTableCellCollection is used to maintain a list of cells belong to a table row. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTableCellCollection extends TControlCollection +{ + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing additional + * operations for each newly added table cell. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a TTableCell object. + */ + public function insertAt($index,$item) + { + if($item instanceof TTableCell) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('tablecellcollection_tablecell_required'); + } +} + + +/** + * TTableRowSection class. + * TTableRowSection defines the enumerable type for the possible table sections + * that a {@link TTableRow} can be within. + * + * The following enumerable values are defined: + * - Header: in table header + * - Body: in table body + * - Footer: in table footer + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTableRowSection extends TEnumerable +{ + const Header='Header'; + const Body='Body'; + const Footer='Footer'; +} + diff --git a/framework/Web/UI/WebControls/TTemplateColumn.php b/framework/Web/UI/WebControls/TTemplateColumn.php index f2bf02d7..34c9bbaf 100644 --- a/framework/Web/UI/WebControls/TTemplateColumn.php +++ b/framework/Web/UI/WebControls/TTemplateColumn.php @@ -1,256 +1,256 @@ -<?php
-/**
- * TTemplateColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTemplateColumn class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TTemplateColumn class
- *
- * TTemplateColumn customizes the layout of controls in the column with templates.
- * In particular, you can specify {@link setItemTemplate ItemTemplate},
- * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate}
- * and {@link setFooterTemplate FooterTemplate} to customize specific
- * type of cells in the column.
- *
- * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
- * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
- * the layout of the datagrid cells in browsing and editing mode.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * When a renderer and a template are both defined for a type of item, the former
- * takes precedence.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTemplateColumn extends TDataGridColumn
-{
- /**
- * Various item templates
- * @var string
- */
- private $_itemTemplate=null;
- private $_editItemTemplate=null;
- private $_headerTemplate=null;
- private $_footerTemplate=null;
-
- /**
- * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the row of the data associated with the datagrid item that this cell resides in.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the edit item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the row of the data associated with the datagrid item that this cell resides in.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the edit item template
- */
- public function getEditItemTemplate()
- {
- return $this->_editItemTemplate;
- }
-
- /**
- * @param ITemplate the edit item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEditItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_editItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate');
- }
-
- /**
- * @return ITemplate the item template
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate');
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template.
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate');
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It initializes the cell based on different templates
- * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate).
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- if($itemType===TListItemType::EditItem)
- {
- if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null)
- {
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- }
- }
- else
- {
- $template=$this->_itemTemplate;
- $classPath=$this->getItemRenderer();
- }
- if($classPath!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($cell->getParent()->getItemIndex());
- $control->setItemType($itemType);
- }
- if($control instanceof IDataRenderer)
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- }
- else if($template!==null)
- $template->instantiateIn($cell);
- else if($itemType!==TListItemType::EditItem)
- $cell->setText(' ');
- }
- else if($itemType===TListItemType::Header)
- {
- if(($classPath=$this->getHeaderRenderer())!=='')
- $this->initializeHeaderCell($cell,$columnIndex);
- else if($this->_headerTemplate!==null)
- $this->_headerTemplate->instantiateIn($cell);
- else
- $this->initializeHeaderCell($cell,$columnIndex);
- }
- else if($itemType===TListItemType::Footer)
- {
- if(($classPath=$this->getFooterRenderer())!=='')
- $this->initializeFooterCell($cell,$columnIndex);
- else if($this->_footerTemplate!==null)
- $this->_footerTemplate->instantiateIn($cell);
- else
- $this->initializeFooterCell($cell,$columnIndex);
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $sender->setData($item->getData());
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TDataGridColumn class file + */ +Prado::using('System.Web.UI.WebControls.TDataGridColumn'); + +/** + * TTemplateColumn class + * + * TTemplateColumn customizes the layout of controls in the column with templates. + * In particular, you can specify {@link setItemTemplate ItemTemplate}, + * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate} + * and {@link setFooterTemplate FooterTemplate} to customize specific + * type of cells in the column. + * + * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer} + * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify + * the layout of the datagrid cells in browsing and editing mode. + * A renderer refers to a control class that is to be instantiated as a control. + * For more details, see {@link TRepeater} and {@link TDataList}. + * + * When a renderer and a template are both defined for a type of item, the former + * takes precedence. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTemplateColumn extends TDataGridColumn +{ + /** + * Various item templates + * @var string + */ + private $_itemTemplate=null; + private $_editItemTemplate=null; + private $_headerTemplate=null; + private $_footerTemplate=null; + + /** + * @return string the class name for the item cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getItemRenderer() + { + return $this->getViewState('ItemRenderer',''); + } + + /** + * Sets the item cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the item cells of the column. + * + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the row of the data associated with the datagrid item that this cell resides in. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setItemRenderer($value) + { + $this->setViewState('ItemRenderer',$value,''); + } + + /** + * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set. + * @since 3.1.0 + */ + public function getEditItemRenderer() + { + return $this->getViewState('EditItemRenderer',''); + } + + /** + * Sets the edit item cell renderer class. + * + * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode. + * + * If the class implements {@link IDataRenderer}, the <b>Data</b> property + * will be set as the row of the data associated with the datagrid item that this cell resides in. + * + * @param string the renderer class name in namespace format. + * @since 3.1.0 + */ + public function setEditItemRenderer($value) + { + $this->setViewState('EditItemRenderer',$value,''); + } + + /** + * @return ITemplate the edit item template + */ + public function getEditItemTemplate() + { + return $this->_editItemTemplate; + } + + /** + * @param ITemplate the edit item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setEditItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_editItemTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate'); + } + + /** + * @return ITemplate the item template + */ + public function getItemTemplate() + { + return $this->_itemTemplate; + } + + /** + * @param ITemplate the item template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setItemTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_itemTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate'); + } + + /** + * @return ITemplate the header template + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate the header template. + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setHeaderTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_headerTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate'); + } + + /** + * @return ITemplate the footer template + */ + public function getFooterTemplate() + { + return $this->_footerTemplate; + } + + /** + * @param ITemplate the footer template + * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null. + */ + public function setFooterTemplate($value) + { + if($value instanceof ITemplate || $value===null) + $this->_footerTemplate=$value; + else + throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate'); + } + + /** + * Initializes the specified cell to its initial values. + * This method overrides the parent implementation. + * It initializes the cell based on different templates + * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate). + * @param TTableCell the cell to be initialized. + * @param integer the index to the Columns property that the cell resides in. + * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem) + */ + public function initializeCell($cell,$columnIndex,$itemType) + { + if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem) + { + if($itemType===TListItemType::EditItem) + { + if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null) + { + $classPath=$this->getItemRenderer(); + $template=$this->_itemTemplate; + } + } + else + { + $template=$this->_itemTemplate; + $classPath=$this->getItemRenderer(); + } + if($classPath!=='') + { + $control=Prado::createComponent($classPath); + $cell->getControls()->add($control); + if($control instanceof IItemDataRenderer) + { + $control->setItemIndex($cell->getParent()->getItemIndex()); + $control->setItemType($itemType); + } + if($control instanceof IDataRenderer) + $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn')); + } + else if($template!==null) + $template->instantiateIn($cell); + else if($itemType!==TListItemType::EditItem) + $cell->setText(' '); + } + else if($itemType===TListItemType::Header) + { + if(($classPath=$this->getHeaderRenderer())!=='') + $this->initializeHeaderCell($cell,$columnIndex); + else if($this->_headerTemplate!==null) + $this->_headerTemplate->instantiateIn($cell); + else + $this->initializeHeaderCell($cell,$columnIndex); + } + else if($itemType===TListItemType::Footer) + { + if(($classPath=$this->getFooterRenderer())!=='') + $this->initializeFooterCell($cell,$columnIndex); + else if($this->_footerTemplate!==null) + $this->_footerTemplate->instantiateIn($cell); + else + $this->initializeFooterCell($cell,$columnIndex); + } + } + + /** + * Databinds a cell in the column. + * This method is invoked when datagrid performs databinding. + * It populates the content of the cell with the relevant data from data source. + */ + public function dataBindColumn($sender,$param) + { + $item=$sender->getNamingContainer(); + $sender->setData($item->getData()); + } +} + diff --git a/framework/Web/UI/WebControls/TTextBox.php b/framework/Web/UI/WebControls/TTextBox.php index 7a9f0445..5cd1149a 100644 --- a/framework/Web/UI/WebControls/TTextBox.php +++ b/framework/Web/UI/WebControls/TTextBox.php @@ -1,652 +1,652 @@ -<?php
-/**
- * TTextBox class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTextBox class
- *
- * TTextBox displays a text box on the Web page for user input.
- * The text displayed in the TTextBox control is determined by the
- * {@link setText Text} property. You can create a <b>SingleLine</b>,
- * a <b>MultiLine</b>, or a <b>Password</b> text box by setting
- * the {@link setTextMode TextMode} property. If the TTextBox control
- * is a multiline text box, the number of rows it displays is determined
- * by the {@link setRows Rows} property, and the {@link setWrap Wrap} property
- * can be used to determine whether to wrap the text in the component.
- *
- * To specify the display width of the text box, in characters, set
- * the {@link setColumns Columns} property. To prevent the text displayed
- * in the component from being modified, set the {@link setReadOnly ReadOnly}
- * property to true. If you want to limit the user input to a specified number
- * of characters, set the {@link setMaxLength MaxLength} property.
- * To use AutoComplete feature, set the {@link setAutoCompleteType AutoCompleteType} property.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, updating the text box
- * and then changing the focus out of it will cause postback action.
- * And if {@link setCausesValidation CausesValidation} is true, validation will
- * also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * WARNING: Be careful if you want to display the text collected via TTextBox.
- * Malicious cross-site script may be injected in. You may use {@link getSafeText SafeText}
- * to prevent this problem.
- *
- * NOTE: If you set {@link setWrap Wrap} to false or use {@link setAutoCompleteType AutoCompleteType},
- * the generated HTML output for the textbox will not be XHTML-compatible.
- * Currently, no alternatives are available.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer
-{
- /**
- * Default number of rows (for MultiLine text box)
- */
- const DEFAULT_ROWS=4;
- /**
- * Default number of columns (for MultiLine text box)
- */
- const DEFAULT_COLUMNS=20;
- /**
- * @var mixed safe text parser
- */
- private static $_safeTextParser=null;
- /**
- * @var string safe textbox content with javascript stripped off
- */
- private $_safeText;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * @return string tag name of the textbox
- */
- protected function getTagName()
- {
- return ($this->getTextMode()==='MultiLine')?'textarea':'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional textbox specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- if(($uid=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uid);
- if(($textMode=$this->getTextMode())===TTextBoxMode::MultiLine)
- {
- if(($rows=$this->getRows())<=0)
- $rows=self::DEFAULT_ROWS;
- if(($cols=$this->getColumns())<=0)
- $cols=self::DEFAULT_COLUMNS;
- $writer->addAttribute('rows',"$rows");
- $writer->addAttribute('cols',"$cols");
- if(!$this->getWrap())
- $writer->addAttribute('wrap','off');
- }
- else
- {
- if($textMode===TTextBoxMode::SingleLine)
- {
- $writer->addAttribute('type','text');
- if(($text=$this->getText())!=='')
- $writer->addAttribute('value',$text);
- }
- else
- {
- if($this->getPersistPassword() && ($text=$this->getText())!=='')
- $writer->addAttribute('value',$text);
- $writer->addAttribute('type','password');
- }
-
- if(($act=$this->getAutoCompleteType())!=='None')
- {
- if($act==='Disabled')
- $writer->addAttribute('autocomplete','off');
- else if($act==='Search')
- $writer->addAttribute('vcard_name','search');
- else if($act==='HomeCountryRegion')
- $writer->addAttribute('vcard_name','HomeCountry');
- else if($act==='BusinessCountryRegion')
- $writer->addAttribute('vcard_name','BusinessCountry');
- else
- {
- if(strpos($act,'Business')===0)
- $act='Business'.'.'.substr($act,8);
- else if(strpos($act,'Home')===0)
- $act='Home'.'.'.substr($act,4);
- $writer->addAttribute('vcard_name','vCard.'.$act);
- }
- }
-
- if(($cols=$this->getColumns())>0)
- $writer->addAttribute('size',"$cols");
- if(($maxLength=$this->getMaxLength())>0)
- $writer->addAttribute('maxlength',"$maxLength");
- }
- if($this->getReadOnly())
- $writer->addAttribute('readonly','readonly');
- $isEnabled=$this->getEnabled(true);
- if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- if($isEnabled
- && $this->getEnableClientScript()
- && ( $this->getAutoPostBack() || $textMode===TTextBoxMode::SingleLine)
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the javascript for textbox.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TTextBox';
- }
-
- /**
- * Gets the post back options for this textbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['AutoPostBack'] = $this->getAutoPostBack();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['TextMode'] = $this->getTextMode();
- return $options;
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=$values[$key];
- if($this->getAutoTrim())
- $value=trim($value);
- if(!$this->getReadOnly() && $this->getText()!==$value)
- {
- $this->setText($value);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getText();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Raises <b>OnTextChanged</b> event.
- * This method is invoked when the value of the {@link getText Text}
- * property changes on postback.
- * If you override this method, be sure to call the parent implementation to ensure
- * the invocation of the attached event handlers.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onTextChanged($param)
- {
- $this->raiseEvent('OnTextChanged',$this,$param);
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getText Text} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onTextChanged(null);
- }
-
- /**
- * Renders the body content of the textbox when it is in MultiLine text mode.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if($this->getTextMode()==='MultiLine')
- $writer->write(THttpUtility::htmlEncode($this->getText()));
- }
-
- /**
- * Renders an additional line-break after the opening tag when it
- * is in MultiLine text mode.
- * @param THtmlWriter the writer used for the rendering purpose^M
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if($this->getTextMode()==='MultiLine')
- $writer->write("\n");
- }
-
- /**
- * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox
- */
- public function getAutoCompleteType()
- {
- return $this->getViewState('AutoCompleteType',TTextBoxAutoCompleteType::None);
- }
-
- /**
- * @param TTextBoxAutoCompleteType the AutoComplete type of the textbox, default value is TTextBoxAutoCompleteType::None.
- * @throws TInvalidDataValueException if the input parameter is not a valid AutoComplete type
- */
- public function setAutoCompleteType($value)
- {
- $this->setViewState('AutoCompleteType',TPropertyValue::ensureEnum($value,'TTextBoxAutoCompleteType'),TTextBoxAutoCompleteType::None);
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user modifies the text in the TTextBox control and
- * then tabs out of the component. Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * modifies the text in the TTextBox control and then tabs out of the component.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean a value indicating whether the input text should be trimmed spaces. Defaults to false.
- */
- public function getAutoTrim()
- {
- return $this->getViewState('AutoTrim',false);
- }
-
- /**
- * Sets the value indicating if the input text should be trimmed spaces
- * @param boolean the value indicating if the input text should be trimmed spaces
- */
- public function setAutoTrim($value)
- {
- $this->setViewState('AutoTrim',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event trigger by this text box will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this text box will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return integer the display width of the text box in characters, default is 0 meaning not set.
- */
- public function getColumns()
- {
- return $this->getViewState('Columns',0);
- }
-
- /**
- * Sets the display width of the text box in characters.
- * @param integer the display width, set it 0 to clear the setting
- */
- public function setColumns($value)
- {
- $this->setViewState('Columns',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the maximum number of characters allowed in the text box, default is 0 meaning not set.
- */
- public function getMaxLength()
- {
- return $this->getViewState('MaxLength',0);
- }
-
- /**
- * Sets the maximum number of characters allowed in the text box.
- * @param integer the maximum length, set it 0 to clear the setting
- */
- public function setMaxLength($value)
- {
- $this->setViewState('MaxLength',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return boolean whether the textbox is read only, default is false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the textbox is read only
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer the number of rows displayed in a multiline text box, default is 4
- */
- public function getRows()
- {
- return $this->getViewState('Rows',self::DEFAULT_ROWS);
- }
-
- /**
- * Sets the number of rows displayed in a multiline text box.
- * @param integer the number of rows
- */
- public function setRows($value)
- {
- $this->setViewState('Rows',TPropertyValue::ensureInteger($value),self::DEFAULT_ROWS);
- }
-
- /**
- * @return boolean whether password should be displayed in the textbox during postback. Defaults to false. This property only applies when TextMode='Password'.
- */
- public function getPersistPassword()
- {
- return $this->getViewState('PersistPassword',false);
- }
-
- /**
- * @param boolean whether password should be displayed in the textbox during postback. This property only applies when TextMode='Password'.
- */
- public function setPersistPassword($value)
- {
- $this->setViewState('PersistPassword',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return string the text content of the TTextBox control.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content of the TTextBox control.
- * @param string the text content
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- $this->_safeText = null;
- }
-
- /**
- * Returns the text content of the TTextBox control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text content of the TTextBox control.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text content of the TTextBox control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text content of the TTextBox control.
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string safe text content with javascript stripped off
- */
- public function getSafeText()
- {
- if($this->_safeText===null)
- $this->_safeText=$this->getSafeTextParser()->parse($this->getText());
- return $this->_safeText;
- }
-
- /**
- * @return mixed safe text parser
- */
- protected function getSafeTextParser()
- {
- if(!self::$_safeTextParser)
- self::$_safeTextParser=Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
- return self::$_safeTextParser;
- }
-
- /**
- * @return TTextBoxMode the behavior mode of the TTextBox component. Defaults to TTextBoxMode::SingleLine.
- */
- public function getTextMode()
- {
- return $this->getViewState('TextMode',TTextBoxMode::SingleLine);
- }
-
- /**
- * Sets the behavior mode of the TTextBox component.
- * @param TTextBoxMode the text mode
- * @throws TInvalidDataValueException if the input value is not a valid text mode.
- */
- public function setTextMode($value)
- {
- $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,'TTextBoxMode'),TTextBoxMode::SingleLine);
- }
-
- /**
- * @return string the group of validators which the text box causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the text box causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return boolean whether the text content wraps within a multiline text box. Defaults to true.
- */
- public function getWrap()
- {
- return $this->getViewState('Wrap',true);
- }
-
- /**
- * Sets the value indicating whether the text content wraps within a multiline text box.
- * @param boolean whether the text content wraps within a multiline text box.
- */
- public function setWrap($value)
- {
- $this->setViewState('Wrap',TPropertyValue::ensureBoolean($value),true);
- }
-}
-
-/**
- * TTextBoxMode class.
- * TTextBoxMode defines the enumerable type for the possible mode
- * that a {@link TTextBox} control could be at.
- *
- * The following enumerable values are defined:
- * - SingleLine: the textbox will be a regular single line input
- * - MultiLine: the textbox will be a textarea allowing multiple line input
- * - Password: the textbox will hide user input like a password input box
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextBoxMode extends TEnumerable
-{
- const SingleLine='SingleLine';
- const MultiLine='MultiLine';
- const Password='Password';
-}
-
-/**
- * TTextBoxAutoCompleteType class.
- * TTextBoxAutoCompleteType defines the possible AutoComplete type that is supported
- * by a {@link TTextBox} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextBoxAutoCompleteType extends TEnumerable
-{
- const BusinessCity='BusinessCity';
- const BusinessCountryRegion='BusinessCountryRegion';
- const BusinessFax='BusinessFax';
- const BusinessPhone='BusinessPhone';
- const BusinessState='BusinessState';
- const BusinessStreetAddress='BusinessStreetAddress';
- const BusinessUrl='BusinessUrl';
- const BusinessZipCode='BusinessZipCode';
- const Cellular='Cellular';
- const Company='Company';
- const Department='Department';
- const Disabled='Disabled';
- const DisplayName='DisplayName';
- const Email='Email';
- const FirstName='FirstName';
- const Gender='Gender';
- const HomeCity='HomeCity';
- const HomeCountryRegion='HomeCountryRegion';
- const HomeFax='HomeFax';
- const Homepage='Homepage';
- const HomePhone='HomePhone';
- const HomeState='HomeState';
- const HomeStreetAddress='HomeStreetAddress';
- const HomeZipCode='HomeZipCode';
- const JobTitle='JobTitle';
- const LastName='LastName';
- const MiddleName='MiddleName';
- const None='None';
- const Notes='Notes';
- const Office='Office';
- const Pager='Pager';
- const Search='Search';
-}
-
+<?php +/** + * TTextBox class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TTextBox class + * + * TTextBox displays a text box on the Web page for user input. + * The text displayed in the TTextBox control is determined by the + * {@link setText Text} property. You can create a <b>SingleLine</b>, + * a <b>MultiLine</b>, or a <b>Password</b> text box by setting + * the {@link setTextMode TextMode} property. If the TTextBox control + * is a multiline text box, the number of rows it displays is determined + * by the {@link setRows Rows} property, and the {@link setWrap Wrap} property + * can be used to determine whether to wrap the text in the component. + * + * To specify the display width of the text box, in characters, set + * the {@link setColumns Columns} property. To prevent the text displayed + * in the component from being modified, set the {@link setReadOnly ReadOnly} + * property to true. If you want to limit the user input to a specified number + * of characters, set the {@link setMaxLength MaxLength} property. + * To use AutoComplete feature, set the {@link setAutoCompleteType AutoCompleteType} property. + * + * If {@link setAutoPostBack AutoPostBack} is set true, updating the text box + * and then changing the focus out of it will cause postback action. + * And if {@link setCausesValidation CausesValidation} is true, validation will + * also be processed, which can be further restricted within + * a {@link setValidationGroup ValidationGroup}. + * + * WARNING: Be careful if you want to display the text collected via TTextBox. + * Malicious cross-site script may be injected in. You may use {@link getSafeText SafeText} + * to prevent this problem. + * + * NOTE: If you set {@link setWrap Wrap} to false or use {@link setAutoCompleteType AutoCompleteType}, + * the generated HTML output for the textbox will not be XHTML-compatible. + * Currently, no alternatives are available. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer +{ + /** + * Default number of rows (for MultiLine text box) + */ + const DEFAULT_ROWS=4; + /** + * Default number of columns (for MultiLine text box) + */ + const DEFAULT_COLUMNS=20; + /** + * @var mixed safe text parser + */ + private static $_safeTextParser=null; + /** + * @var string safe textbox content with javascript stripped off + */ + private $_safeText; + private $_dataChanged=false; + private $_isValid=true; + + /** + * @return string tag name of the textbox + */ + protected function getTagName() + { + return ($this->getTextMode()==='MultiLine')?'textarea':'input'; + } + + /** + * @return boolean whether to render javascript. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether to render javascript. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation with additional textbox specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + $page=$this->getPage(); + $page->ensureRenderInForm($this); + if(($uid=$this->getUniqueID())!=='') + $writer->addAttribute('name',$uid); + if(($textMode=$this->getTextMode())===TTextBoxMode::MultiLine) + { + if(($rows=$this->getRows())<=0) + $rows=self::DEFAULT_ROWS; + if(($cols=$this->getColumns())<=0) + $cols=self::DEFAULT_COLUMNS; + $writer->addAttribute('rows',"$rows"); + $writer->addAttribute('cols',"$cols"); + if(!$this->getWrap()) + $writer->addAttribute('wrap','off'); + } + else + { + if($textMode===TTextBoxMode::SingleLine) + { + $writer->addAttribute('type','text'); + if(($text=$this->getText())!=='') + $writer->addAttribute('value',$text); + } + else + { + if($this->getPersistPassword() && ($text=$this->getText())!=='') + $writer->addAttribute('value',$text); + $writer->addAttribute('type','password'); + } + + if(($act=$this->getAutoCompleteType())!=='None') + { + if($act==='Disabled') + $writer->addAttribute('autocomplete','off'); + else if($act==='Search') + $writer->addAttribute('vcard_name','search'); + else if($act==='HomeCountryRegion') + $writer->addAttribute('vcard_name','HomeCountry'); + else if($act==='BusinessCountryRegion') + $writer->addAttribute('vcard_name','BusinessCountry'); + else + { + if(strpos($act,'Business')===0) + $act='Business'.'.'.substr($act,8); + else if(strpos($act,'Home')===0) + $act='Home'.'.'.substr($act,4); + $writer->addAttribute('vcard_name','vCard.'.$act); + } + } + + if(($cols=$this->getColumns())>0) + $writer->addAttribute('size',"$cols"); + if(($maxLength=$this->getMaxLength())>0) + $writer->addAttribute('maxlength',"$maxLength"); + } + if($this->getReadOnly()) + $writer->addAttribute('readonly','readonly'); + $isEnabled=$this->getEnabled(true); + if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled' + $writer->addAttribute('disabled','disabled'); + if($isEnabled + && $this->getEnableClientScript() + && ( $this->getAutoPostBack() || $textMode===TTextBoxMode::SingleLine) + && $page->getClientSupportsJavaScript()) + { + $this->renderClientControlScript($writer); + } + parent::addAttributesToRender($writer); + } + + /** + * Renders the javascript for textbox. + */ + protected function renderClientControlScript($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $cs = $this->getPage()->getClientScript(); + $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions()); + } + + /** + * Gets the name of the javascript class responsible for performing postback for this control. + * This method overrides the parent implementation. + * @return string the javascript class name + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TTextBox'; + } + + /** + * Gets the post back options for this textbox. + * @return array + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + $options['AutoPostBack'] = $this->getAutoPostBack(); + $options['CausesValidation'] = $this->getCausesValidation(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['TextMode'] = $this->getTextMode(); + return $options; + } + + /** + * Loads user input data. + * This method is primarly used by framework developers. + * @param string the key that can be used to retrieve data from the input data collection + * @param array the input data collection + * @return boolean whether the data of the component has been changed + */ + public function loadPostData($key,$values) + { + $value=$values[$key]; + if($this->getAutoTrim()) + $value=trim($value); + if(!$this->getReadOnly() && $this->getText()!==$value) + { + $this->setText($value); + return $this->_dataChanged=true; + } + else + return false; + } + + /** + * Returns a value indicating whether postback has caused the control data change. + * This method is required by the IPostBackDataHandler interface. + * @return boolean whether postback has caused the control data change. False if the page is not in postback mode. + */ + public function getDataChanged() + { + return $this->_dataChanged; + } + + /** + * Returns the value to be validated. + * This methid is required by IValidatable interface. + * @return mixed the value of the property to be validated. + */ + public function getValidationPropertyValue() + { + return $this->getText(); + } + + /** + * Returns true if this control validated successfully. + * Defaults to true. + * @return bool wether this control validated successfully. + */ + public function getIsValid() + { + return $this->_isValid; + } + /** + * @param bool wether this control is valid. + */ + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + + /** + * Raises <b>OnTextChanged</b> event. + * This method is invoked when the value of the {@link getText Text} + * property changes on postback. + * If you override this method, be sure to call the parent implementation to ensure + * the invocation of the attached event handlers. + * @param TEventParameter event parameter to be passed to the event handlers + */ + public function onTextChanged($param) + { + $this->raiseEvent('OnTextChanged',$this,$param); + } + + /** + * Raises postdata changed event. + * This method is required by {@link IPostBackDataHandler} interface. + * It is invoked by the framework when {@link getText Text} property + * is changed on postback. + * This method is primarly used by framework developers. + */ + public function raisePostDataChangedEvent() + { + if($this->getAutoPostBack() && $this->getCausesValidation()) + $this->getPage()->validate($this->getValidationGroup()); + $this->onTextChanged(null); + } + + /** + * Renders the body content of the textbox when it is in MultiLine text mode. + * @param THtmlWriter the writer for rendering + */ + public function renderContents($writer) + { + if($this->getTextMode()==='MultiLine') + $writer->write(THttpUtility::htmlEncode($this->getText())); + } + + /** + * Renders an additional line-break after the opening tag when it + * is in MultiLine text mode. + * @param THtmlWriter the writer used for the rendering purpose^M + */ + public function renderBeginTag($writer) + { + parent::renderBeginTag($writer); + if($this->getTextMode()==='MultiLine') + $writer->write("\n"); + } + + /** + * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox + */ + public function getAutoCompleteType() + { + return $this->getViewState('AutoCompleteType',TTextBoxAutoCompleteType::None); + } + + /** + * @param TTextBoxAutoCompleteType the AutoComplete type of the textbox, default value is TTextBoxAutoCompleteType::None. + * @throws TInvalidDataValueException if the input parameter is not a valid AutoComplete type + */ + public function setAutoCompleteType($value) + { + $this->setViewState('AutoCompleteType',TPropertyValue::ensureEnum($value,'TTextBoxAutoCompleteType'),TTextBoxAutoCompleteType::None); + } + + /** + * @return boolean a value indicating whether an automatic postback to the server + * will occur whenever the user modifies the text in the TTextBox control and + * then tabs out of the component. Defaults to false. + */ + public function getAutoPostBack() + { + return $this->getViewState('AutoPostBack',false); + } + + /** + * Sets the value indicating if postback automatically. + * An automatic postback to the server will occur whenever the user + * modifies the text in the TTextBox control and then tabs out of the component. + * @param boolean the value indicating if postback automatically + */ + public function setAutoPostBack($value) + { + $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean a value indicating whether the input text should be trimmed spaces. Defaults to false. + */ + public function getAutoTrim() + { + return $this->getViewState('AutoTrim',false); + } + + /** + * Sets the value indicating if the input text should be trimmed spaces + * @param boolean the value indicating if the input text should be trimmed spaces + */ + public function setAutoTrim($value) + { + $this->setViewState('AutoTrim',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether postback event trigger by this text box will cause input validation, default is true. + */ + public function getCausesValidation() + { + return $this->getViewState('CausesValidation',true); + } + + /** + * @param boolean whether postback event trigger by this text box will cause input validation. + */ + public function setCausesValidation($value) + { + $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return integer the display width of the text box in characters, default is 0 meaning not set. + */ + public function getColumns() + { + return $this->getViewState('Columns',0); + } + + /** + * Sets the display width of the text box in characters. + * @param integer the display width, set it 0 to clear the setting + */ + public function setColumns($value) + { + $this->setViewState('Columns',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return integer the maximum number of characters allowed in the text box, default is 0 meaning not set. + */ + public function getMaxLength() + { + return $this->getViewState('MaxLength',0); + } + + /** + * Sets the maximum number of characters allowed in the text box. + * @param integer the maximum length, set it 0 to clear the setting + */ + public function setMaxLength($value) + { + $this->setViewState('MaxLength',TPropertyValue::ensureInteger($value),0); + } + + /** + * @return boolean whether the textbox is read only, default is false. + */ + public function getReadOnly() + { + return $this->getViewState('ReadOnly',false); + } + + /** + * @param boolean whether the textbox is read only + */ + public function setReadOnly($value) + { + $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return integer the number of rows displayed in a multiline text box, default is 4 + */ + public function getRows() + { + return $this->getViewState('Rows',self::DEFAULT_ROWS); + } + + /** + * Sets the number of rows displayed in a multiline text box. + * @param integer the number of rows + */ + public function setRows($value) + { + $this->setViewState('Rows',TPropertyValue::ensureInteger($value),self::DEFAULT_ROWS); + } + + /** + * @return boolean whether password should be displayed in the textbox during postback. Defaults to false. This property only applies when TextMode='Password'. + */ + public function getPersistPassword() + { + return $this->getViewState('PersistPassword',false); + } + + /** + * @param boolean whether password should be displayed in the textbox during postback. This property only applies when TextMode='Password'. + */ + public function setPersistPassword($value) + { + $this->setViewState('PersistPassword',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return string the text content of the TTextBox control. + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * Sets the text content of the TTextBox control. + * @param string the text content + */ + public function setText($value) + { + $this->setViewState('Text',$value,''); + $this->_safeText = null; + } + + /** + * Returns the text content of the TTextBox control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link getText()}. + * @return string the text content of the TTextBox control. + * @see getText + * @since 3.1.0 + */ + public function getData() + { + return $this->getText(); + } + + /** + * Sets the text content of the TTextBox control. + * This method is required by {@link IDataRenderer}. + * It is the same as {@link setText()}. + * @param string the text content of the TTextBox control. + * @see setText + * @since 3.1.0 + */ + public function setData($value) + { + $this->setText($value); + } + + /** + * @return string safe text content with javascript stripped off + */ + public function getSafeText() + { + if($this->_safeText===null) + $this->_safeText=$this->getSafeTextParser()->parse($this->getText()); + return $this->_safeText; + } + + /** + * @return mixed safe text parser + */ + protected function getSafeTextParser() + { + if(!self::$_safeTextParser) + self::$_safeTextParser=Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser'); + return self::$_safeTextParser; + } + + /** + * @return TTextBoxMode the behavior mode of the TTextBox component. Defaults to TTextBoxMode::SingleLine. + */ + public function getTextMode() + { + return $this->getViewState('TextMode',TTextBoxMode::SingleLine); + } + + /** + * Sets the behavior mode of the TTextBox component. + * @param TTextBoxMode the text mode + * @throws TInvalidDataValueException if the input value is not a valid text mode. + */ + public function setTextMode($value) + { + $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,'TTextBoxMode'),TTextBoxMode::SingleLine); + } + + /** + * @return string the group of validators which the text box causes validation upon postback + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group of validators which the text box causes validation upon postback + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + /** + * @return boolean whether the text content wraps within a multiline text box. Defaults to true. + */ + public function getWrap() + { + return $this->getViewState('Wrap',true); + } + + /** + * Sets the value indicating whether the text content wraps within a multiline text box. + * @param boolean whether the text content wraps within a multiline text box. + */ + public function setWrap($value) + { + $this->setViewState('Wrap',TPropertyValue::ensureBoolean($value),true); + } +} + +/** + * TTextBoxMode class. + * TTextBoxMode defines the enumerable type for the possible mode + * that a {@link TTextBox} control could be at. + * + * The following enumerable values are defined: + * - SingleLine: the textbox will be a regular single line input + * - MultiLine: the textbox will be a textarea allowing multiple line input + * - Password: the textbox will hide user input like a password input box + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTextBoxMode extends TEnumerable +{ + const SingleLine='SingleLine'; + const MultiLine='MultiLine'; + const Password='Password'; +} + +/** + * TTextBoxAutoCompleteType class. + * TTextBoxAutoCompleteType defines the possible AutoComplete type that is supported + * by a {@link TTextBox} control. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TTextBoxAutoCompleteType extends TEnumerable +{ + const BusinessCity='BusinessCity'; + const BusinessCountryRegion='BusinessCountryRegion'; + const BusinessFax='BusinessFax'; + const BusinessPhone='BusinessPhone'; + const BusinessState='BusinessState'; + const BusinessStreetAddress='BusinessStreetAddress'; + const BusinessUrl='BusinessUrl'; + const BusinessZipCode='BusinessZipCode'; + const Cellular='Cellular'; + const Company='Company'; + const Department='Department'; + const Disabled='Disabled'; + const DisplayName='DisplayName'; + const Email='Email'; + const FirstName='FirstName'; + const Gender='Gender'; + const HomeCity='HomeCity'; + const HomeCountryRegion='HomeCountryRegion'; + const HomeFax='HomeFax'; + const Homepage='Homepage'; + const HomePhone='HomePhone'; + const HomeState='HomeState'; + const HomeStreetAddress='HomeStreetAddress'; + const HomeZipCode='HomeZipCode'; + const JobTitle='JobTitle'; + const LastName='LastName'; + const MiddleName='MiddleName'; + const None='None'; + const Notes='Notes'; + const Office='Office'; + const Pager='Pager'; + const Search='Search'; +} + diff --git a/framework/Web/UI/WebControls/TTextProcessor.php b/framework/Web/UI/WebControls/TTextProcessor.php index 6d95a482..60d047fe 100644 --- a/framework/Web/UI/WebControls/TTextProcessor.php +++ b/framework/Web/UI/WebControls/TTextProcessor.php @@ -1,86 +1,86 @@ -<?php
-/**
- * TTextProcessor class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TTextProcessor class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTextProcessor class.
- *
- * TTextProcessor is the base class for classes that process or transform
- * text content into different forms. The text content to be processed
- * is specified by {@link setText Text} property. If it is not set, the body
- * content enclosed within the processor control will be processed and rendered.
- * The body content includes static text strings and the rendering result
- * of child controls.
- *
- * Note, all child classes must implement {@link processText} method.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0.1
- */
-abstract class TTextProcessor extends TWebControl
-{
- /**
- * Processes a text string.
- * This method must be implemented by child classes.
- * @param string text string to be processed
- * @return string the processed text result
- */
- abstract public function processText($text);
-
- /**
- * HTML-decodes static text.
- * This method overrides parent implementation.
- * @param mixed object to be added as body content
- */
- public function addParsedObject($object)
- {
- if(is_string($object))
- $object=html_entity_decode($object,ENT_QUOTES,'UTF-8');
- parent::addParsedObject($object);
- }
-
- /**
- * @return string text to be processed
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string text to be processed
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value);
- }
-
- /**
- * Renders body content.
- * This method overrides the parent implementation by replacing
- * the body content with the processed text content.
- * @param THtmlWriter writer
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='' && $this->getHasControls())
- {
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
- parent::renderContents($htmlWriter);
- $text=$htmlWriter->flush();
- }
- if($text!=='')
- $writer->write($this->processText($text));
- }
-
-}
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TTextProcessor class. + * + * TTextProcessor is the base class for classes that process or transform + * text content into different forms. The text content to be processed + * is specified by {@link setText Text} property. If it is not set, the body + * content enclosed within the processor control will be processed and rendered. + * The body content includes static text strings and the rendering result + * of child controls. + * + * Note, all child classes must implement {@link processText} method. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI + * @since 3.0.1 + */ +abstract class TTextProcessor extends TWebControl +{ + /** + * Processes a text string. + * This method must be implemented by child classes. + * @param string text string to be processed + * @return string the processed text result + */ + abstract public function processText($text); + + /** + * HTML-decodes static text. + * This method overrides parent implementation. + * @param mixed object to be added as body content + */ + public function addParsedObject($object) + { + if(is_string($object)) + $object=html_entity_decode($object,ENT_QUOTES,'UTF-8'); + parent::addParsedObject($object); + } + + /** + * @return string text to be processed + */ + public function getText() + { + return $this->getViewState('Text',''); + } + + /** + * @param string text to be processed + */ + public function setText($value) + { + $this->setViewState('Text',$value); + } + + /** + * Renders body content. + * This method overrides the parent implementation by replacing + * the body content with the processed text content. + * @param THtmlWriter writer + */ + public function renderContents($writer) + { + if(($text=$this->getText())==='' && $this->getHasControls()) + { + $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter()); + parent::renderContents($htmlWriter); + $text=$htmlWriter->flush(); + } + if($text!=='') + $writer->write($this->processText($text)); + } + +} diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php index 6c258927..c915d163 100644 --- a/framework/Web/UI/WebControls/TValidationSummary.php +++ b/framework/Web/UI/WebControls/TValidationSummary.php @@ -1,536 +1,536 @@ -<?php
-/**
- * TValidationSummary class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TValidationSummary class
- *
- * TValidationSummary displays a summary of validation errors inline on a Web page,
- * in a message box, or both. By default, a validation summary will collect
- * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators
- * on the page. If {@link getValidationGroup ValidationGroup} is not
- * empty, only those validators who belong to the group will show their error messages
- * in the summary.
- *
- * The summary can be displayed as a list, as a bulleted list, or as a single
- * paragraph based on the {@link setDisplayMode DisplayMode} property.
- * The messages shown can be prefixed with {@link setHeaderText HeaderText}.
- *
- * The summary can be displayed on the Web page and in a message box by setting
- * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox}
- * properties, respectively. Note, the latter is only effective when
- * {@link setEnableClientScript EnableClientScript} is true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TValidationSummary extends TWebControl
-{
- /**
- * @var TClientSideValidationSummaryOptions validation client side options.
- */
- private $_clientSide;
-
- /**
- * Constructor.
- * This method sets the foreground color to red.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setForeColor('red');
- }
-
- /**
- * @return TValidationSummaryDisplayStyle the style of displaying the error messages. Defaults to TValidationSummaryDisplayStyle::Fixed.
- */
- public function getDisplay()
- {
- return $this->getViewState('Display',TValidationSummaryDisplayStyle::Fixed);
- }
-
- /**
- * @param TValidationSummaryDisplayStyle the style of displaying the error messages
- */
- public function setDisplay($value)
- {
- $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayStyle'),TValidationSummaryDisplayStyle::Fixed);
- }
-
- /**
- * @return string the header text displayed at the top of the summary
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * Sets the header text to be displayed at the top of the summary
- * @param string the header text
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',$value,'');
- }
-
- /**
- * @return TValidationSummaryDisplayMode the mode of displaying error messages. Defaults to TValidationSummaryDisplayMode::BulletList.
- */
- public function getDisplayMode()
- {
- return $this->getViewState('DisplayMode',TValidationSummaryDisplayMode::BulletList);
- }
-
- /**
- * @param TValidationSummaryDisplayMode the mode of displaying error messages
- */
- public function setDisplayMode($value)
- {
- $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayMode'),TValidationSummaryDisplayMode::BulletList);
- }
-
- /**
- * @return boolean whether the TValidationSummary component updates itself using client-side script. Defaults to true.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether the TValidationSummary component updates itself using client-side script.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the validation summary is displayed in a message box. Defaults to false.
- */
- public function getShowMessageBox()
- {
- return $this->getViewState('ShowMessageBox',false);
- }
-
- /**
- * @param boolean whether the validation summary is displayed in a message box.
- */
- public function setShowMessageBox($value)
- {
- $this->setViewState('ShowMessageBox',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the validation summary is displayed inline. Defaults to true.
- */
- public function getShowSummary()
- {
- return $this->getViewState('ShowSummary',true);
- }
-
- /**
- * @param boolean whether the validation summary is displayed inline.
- */
- public function setShowSummary($value)
- {
- $this->setViewState('ShowSummary',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether scroll summary into viewport or not. Defaults to true.
- */
- public function getScrollToSummary()
- {
- return $this->getViewState('ScrollToSummary',true);
- }
-
- /**
- * @param boolean whether scroll summary into viewport or not.
- */
- public function setScrollToSummary($value)
- {
- $this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the validation summary should be anchored. Defaults to false.
- */
- public function getShowAnchor()
- {
- return $this->getViewState('ShowAnchor',false);
- }
-
- /**
- * @param boolean whether the validation summary should be anchored.
- */
- public function setShowAnchor($value)
- {
- $this->setViewState('ShowAnchor',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Gets the auto-update for this summary.
- * @return boolean automatic client-side summary updates. Defaults to true.
- */
- public function getAutoUpdate()
- {
- return $this->getViewState('AutoUpdate', true);
- }
-
- /**
- * Sets the summary to auto-update on the client-side
- * @param boolean true for automatic summary updates.
- */
- public function setAutoUpdate($value)
- {
- $this->setViewState('AutoUpdate', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return string the group which this validator belongs to
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group which this validator belongs to
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- protected function addAttributesToRender($writer)
- {
- $display=$this->getDisplay();
- $visible=$this->getEnabled(true) && count($this->getErrorMessages()) > 0;
- if(!$visible)
- {
- if($display===TValidationSummaryDisplayStyle::None || $display===TValidationSummaryDisplayStyle::Dynamic)
- $writer->addStyleAttribute('display','none');
- else
- $writer->addStyleAttribute('visibility','hidden');
- }
- $writer->addAttribute('id',$this->getClientID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Render the javascript for validation summary.
- * @param array list of options for validation summary.
- */
- protected function renderJsSummary()
- {
- if(!$this->getEnabled(true) || !$this->getEnableClientScript())
- return;
- $cs = $this->getPage()->getClientScript();
- $cs->registerPradoScript('validator');
-
- //need to register the validation manager is validation summary is alone.
- $formID=$this->getPage()->getForm()->getClientID();
- $scriptKey = "TBaseValidator:$formID";
- if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey))
- {
- $manager['FormID'] = $formID;
- $options = TJavaScript::encode($manager);
- $cs->registerPradoScript('validator');
- $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
- }
-
-
- $options=TJavaScript::encode($this->getClientScriptOptions());
- $script = "new Prado.WebUI.TValidationSummary({$options});";
- $cs->registerEndScript($this->getClientID(), $script);
- }
-
- /**
- * Get a list of options for the client-side javascript validation summary.
- * @return array list of options for the summary
- */
- protected function getClientScriptOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['FormID'] = $this->getPage()->getForm()->getClientID();
- if($this->getShowMessageBox())
- $options['ShowMessageBox']=true;
- if(!$this->getShowSummary())
- $options['ShowSummary']=false;
-
- $options['ScrollToSummary']=$this->getScrollToSummary();
- $options['HeaderText']=$this->getHeaderText();
- $options['DisplayMode']=$this->getDisplayMode();
-
- $options['Refresh'] = $this->getAutoUpdate();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['Display'] = $this->getDisplay();
-
- if($this->_clientSide!==null)
- $options = array_merge($options,$this->_clientSide->getOptions()->toArray());
-
- return $options;
- }
-
- /**
- * @return TClientSideValidationSummaryOptions client-side validation summary
- * event options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientScript();
- return $this->_clientSide;
- }
-
- /**
- * @return TClientSideValidationSummaryOptions javascript validation summary
- * event options.
- */
- protected function createClientScript()
- {
- return new TClientSideValidationSummaryOptions;
- }
- /**
- * Get the list of validation error messages.
- * @return array list of validator error messages.
- */
- protected function getErrorMessages()
- {
- $validators=$this->getPage()->getValidators($this->getValidationGroup());
- $messages = array();
- foreach($validators as $validator)
- {
- if(!$validator->getIsValid() && ($msg=$validator->getErrorMessage())!=='')
- //$messages[] = $validator->getAnchoredMessage($msg);
- $messages[] = $msg;
- }
- return $messages;
- }
-
- /**
- * Overrides parent implementation by rendering TValidationSummary-specific presentation.
- * @return string the rendering result
- */
- public function renderContents($writer)
- {
- $this->renderJsSummary();
- if($this->getShowSummary())
- {
-// $this->setStyle('display:block');
- switch($this->getDisplayMode())
- {
- case TValidationSummaryDisplayMode::SimpleList:
- $this->renderList($writer);
- break;
- case TValidationSummaryDisplayMode::SingleParagraph:
- $this->renderSingleParagraph($writer);
- break;
- case TValidationSummaryDisplayMode::BulletList:
- $this->renderBulletList($writer);
- break;
- case TValidationSummaryDisplayMode::HeaderOnly:
- $this->renderHeaderOnly($writer);
- break;
- }
- }
- }
-
- /**
- * Render the validation summary as a simple list.
- * @param array list of messages
- * @param string the header text
- * @return string summary list
- */
- protected function renderList($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = '';
- if(strlen($header))
- $content.= $header."<br/>\n";
- foreach($messages as $message)
- $content.="$message<br/>\n";
- $writer->write($content);
- }
-
- /**
- * Render the validation summary as a paragraph.
- * @param array list of messages
- * @param string the header text
- * @return string summary paragraph
- */
- protected function renderSingleParagraph($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = $header;
- foreach($messages as $message)
- $content.= ' '.$message;
- $writer->write($content);
- }
-
- /**
- * Render the validation summary as a bullet list.
- * @param array list of messages
- * @param string the header text
- * @return string summary bullet list
- */
- protected function renderBulletList($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = $header;
- if(count($messages)>0)
- {
- $content .= "<ul>\n";
- foreach($messages as $message)
- $content.= '<li>'.$message."</li>\n";
- $content .= "</ul>\n";
- }
- $writer->write($content);
- }
-
- /**
- * Render the validation summary header text only.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function renderHeaderOnly($writer)
- {
- $writer->write($this->getHeaderText());
- }
-}
-
-/**
- * TClientSideValidationSummaryOptions class.
- *
- * Client-side validation summary events such as {@link setOnHideSummary
- * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified
- * through the {@link TBaseValidator:: getClientSide ClientSide} property of a
- * validation summary.
- *
- * The <tt>OnHideSummary</tt> event is raise when the validation summary
- * requests to hide the messages.
- *
- * The <tt>OnShowSummary</tt> event is raised when the validation summary
- * requests to show the messages.
- *
- * See the quickstart documentation for further details.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TClientSideValidationSummaryOptions extends TClientSideOptions
-{
- /**
- * @return string javascript code for client-side OnHideSummary event.
- */
- public function getOnHideSummary()
- {
- return $this->getOption('OnHideSummary');
- }
-
- /**
- * Client-side OnHideSummary validation summary event is raise when all the
- * validators are valid. This will override the default client-side
- * validation summary behaviour.
- * @param string javascript code for client-side OnHideSummary event.
- */
- public function setOnHideSummary($javascript)
- {
- $this->setFunction('OnHideSummary', $javascript);
- }
-
- /**
- * Client-side OnShowSummary event is raise when one or more validators are
- * not valid. This will override the default client-side validation summary
- * behaviour.
- * @param string javascript code for client-side OnShowSummary event.
- */
- public function setOnShowSummary($javascript)
- {
- $this->setFunction('OnShowSummary', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnShowSummary event.
- */
- public function getOnShowSummary()
- {
- return $this->getOption('OnShowSummary');
- }
-
- /**
- * Ensure the string is a valid javascript function. The code block
- * is enclosed with "function(summary, validators){ }" block.
- * @param string javascript code.
- * @return string javascript function code.
- */
- protected function ensureFunction($javascript)
- {
- return "function(summary, validators){ {$javascript} }";
- }
-}
-
-
-/**
- * TValidationSummaryDisplayMode class.
- * TValidationSummaryDisplayMode defines the enumerable type for the possible modes
- * that a {@link TValidationSummary} can organize and display the collected error messages.
- *
- * The following enumerable values are defined:
- * - SimpleList: the error messages are displayed as a list without any decorations.
- * - SingleParagraph: the error messages are concatenated together into a paragraph.
- * - BulletList: the error messages are displayed as a bulleted list.
- * - HeaderOnly: only the HeaderText will be display.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationSummaryDisplayMode extends TEnumerable
-{
- const SimpleList='SimpleList';
- const SingleParagraph='SingleParagraph';
- const BulletList='BulletList';
- const HeaderOnly='HeaderOnly';
-}
-
-
-/**
- * TValidationSummaryDisplay class.
- * TValidationSummaryDisplay defines the enumerable type for the possible styles
- * that a {@link TValidationSummary} can display the collected error messages.
- *
- * The following enumerable values are defined:
- * - None: the error messages are not displayed
- * - Dynamic: the error messages are dynamically added to display as the corresponding validators fail
- * - Fixed: Similar to Dynamic except that the error messages physically occupy the page layout (even though they may not be visible)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationSummaryDisplayStyle extends TEnumerable
-{
- const None='None';
- const Dynamic='Dynamic';
- const Fixed='Fixed';
-}
-
+<?php +/** + * TValidationSummary class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TValidationSummary class + * + * TValidationSummary displays a summary of validation errors inline on a Web page, + * in a message box, or both. By default, a validation summary will collect + * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators + * on the page. If {@link getValidationGroup ValidationGroup} is not + * empty, only those validators who belong to the group will show their error messages + * in the summary. + * + * The summary can be displayed as a list, as a bulleted list, or as a single + * paragraph based on the {@link setDisplayMode DisplayMode} property. + * The messages shown can be prefixed with {@link setHeaderText HeaderText}. + * + * The summary can be displayed on the Web page and in a message box by setting + * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox} + * properties, respectively. Note, the latter is only effective when + * {@link setEnableClientScript EnableClientScript} is true. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TValidationSummary extends TWebControl +{ + /** + * @var TClientSideValidationSummaryOptions validation client side options. + */ + private $_clientSide; + + /** + * Constructor. + * This method sets the foreground color to red. + */ + public function __construct() + { + parent::__construct(); + $this->setForeColor('red'); + } + + /** + * @return TValidationSummaryDisplayStyle the style of displaying the error messages. Defaults to TValidationSummaryDisplayStyle::Fixed. + */ + public function getDisplay() + { + return $this->getViewState('Display',TValidationSummaryDisplayStyle::Fixed); + } + + /** + * @param TValidationSummaryDisplayStyle the style of displaying the error messages + */ + public function setDisplay($value) + { + $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayStyle'),TValidationSummaryDisplayStyle::Fixed); + } + + /** + * @return string the header text displayed at the top of the summary + */ + public function getHeaderText() + { + return $this->getViewState('HeaderText',''); + } + + /** + * Sets the header text to be displayed at the top of the summary + * @param string the header text + */ + public function setHeaderText($value) + { + $this->setViewState('HeaderText',$value,''); + } + + /** + * @return TValidationSummaryDisplayMode the mode of displaying error messages. Defaults to TValidationSummaryDisplayMode::BulletList. + */ + public function getDisplayMode() + { + return $this->getViewState('DisplayMode',TValidationSummaryDisplayMode::BulletList); + } + + /** + * @param TValidationSummaryDisplayMode the mode of displaying error messages + */ + public function setDisplayMode($value) + { + $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayMode'),TValidationSummaryDisplayMode::BulletList); + } + + /** + * @return boolean whether the TValidationSummary component updates itself using client-side script. Defaults to true. + */ + public function getEnableClientScript() + { + return $this->getViewState('EnableClientScript',true); + } + + /** + * @param boolean whether the TValidationSummary component updates itself using client-side script. + */ + public function setEnableClientScript($value) + { + $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the validation summary is displayed in a message box. Defaults to false. + */ + public function getShowMessageBox() + { + return $this->getViewState('ShowMessageBox',false); + } + + /** + * @param boolean whether the validation summary is displayed in a message box. + */ + public function setShowMessageBox($value) + { + $this->setViewState('ShowMessageBox',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether the validation summary is displayed inline. Defaults to true. + */ + public function getShowSummary() + { + return $this->getViewState('ShowSummary',true); + } + + /** + * @param boolean whether the validation summary is displayed inline. + */ + public function setShowSummary($value) + { + $this->setViewState('ShowSummary',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether scroll summary into viewport or not. Defaults to true. + */ + public function getScrollToSummary() + { + return $this->getViewState('ScrollToSummary',true); + } + + /** + * @param boolean whether scroll summary into viewport or not. + */ + public function setScrollToSummary($value) + { + $this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return boolean whether the validation summary should be anchored. Defaults to false. + */ + public function getShowAnchor() + { + return $this->getViewState('ShowAnchor',false); + } + + /** + * @param boolean whether the validation summary should be anchored. + */ + public function setShowAnchor($value) + { + $this->setViewState('ShowAnchor',TPropertyValue::ensureBoolean($value),false); + } + + /** + * Gets the auto-update for this summary. + * @return boolean automatic client-side summary updates. Defaults to true. + */ + public function getAutoUpdate() + { + return $this->getViewState('AutoUpdate', true); + } + + /** + * Sets the summary to auto-update on the client-side + * @param boolean true for automatic summary updates. + */ + public function setAutoUpdate($value) + { + $this->setViewState('AutoUpdate', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return string the group which this validator belongs to + */ + public function getValidationGroup() + { + return $this->getViewState('ValidationGroup',''); + } + + /** + * @param string the group which this validator belongs to + */ + public function setValidationGroup($value) + { + $this->setViewState('ValidationGroup',$value,''); + } + + protected function addAttributesToRender($writer) + { + $display=$this->getDisplay(); + $visible=$this->getEnabled(true) && count($this->getErrorMessages()) > 0; + if(!$visible) + { + if($display===TValidationSummaryDisplayStyle::None || $display===TValidationSummaryDisplayStyle::Dynamic) + $writer->addStyleAttribute('display','none'); + else + $writer->addStyleAttribute('visibility','hidden'); + } + $writer->addAttribute('id',$this->getClientID()); + parent::addAttributesToRender($writer); + } + + /** + * Render the javascript for validation summary. + * @param array list of options for validation summary. + */ + protected function renderJsSummary() + { + if(!$this->getEnabled(true) || !$this->getEnableClientScript()) + return; + $cs = $this->getPage()->getClientScript(); + $cs->registerPradoScript('validator'); + + //need to register the validation manager is validation summary is alone. + $formID=$this->getPage()->getForm()->getClientID(); + $scriptKey = "TBaseValidator:$formID"; + if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey)) + { + $manager['FormID'] = $formID; + $options = TJavaScript::encode($manager); + $cs->registerPradoScript('validator'); + $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});"); + } + + + $options=TJavaScript::encode($this->getClientScriptOptions()); + $script = "new Prado.WebUI.TValidationSummary({$options});"; + $cs->registerEndScript($this->getClientID(), $script); + } + + /** + * Get a list of options for the client-side javascript validation summary. + * @return array list of options for the summary + */ + protected function getClientScriptOptions() + { + $options['ID'] = $this->getClientID(); + $options['FormID'] = $this->getPage()->getForm()->getClientID(); + if($this->getShowMessageBox()) + $options['ShowMessageBox']=true; + if(!$this->getShowSummary()) + $options['ShowSummary']=false; + + $options['ScrollToSummary']=$this->getScrollToSummary(); + $options['HeaderText']=$this->getHeaderText(); + $options['DisplayMode']=$this->getDisplayMode(); + + $options['Refresh'] = $this->getAutoUpdate(); + $options['ValidationGroup'] = $this->getValidationGroup(); + $options['Display'] = $this->getDisplay(); + + if($this->_clientSide!==null) + $options = array_merge($options,$this->_clientSide->getOptions()->toArray()); + + return $options; + } + + /** + * @return TClientSideValidationSummaryOptions client-side validation summary + * event options. + */ + public function getClientSide() + { + if($this->_clientSide===null) + $this->_clientSide = $this->createClientScript(); + return $this->_clientSide; + } + + /** + * @return TClientSideValidationSummaryOptions javascript validation summary + * event options. + */ + protected function createClientScript() + { + return new TClientSideValidationSummaryOptions; + } + /** + * Get the list of validation error messages. + * @return array list of validator error messages. + */ + protected function getErrorMessages() + { + $validators=$this->getPage()->getValidators($this->getValidationGroup()); + $messages = array(); + foreach($validators as $validator) + { + if(!$validator->getIsValid() && ($msg=$validator->getErrorMessage())!=='') + //$messages[] = $validator->getAnchoredMessage($msg); + $messages[] = $msg; + } + return $messages; + } + + /** + * Overrides parent implementation by rendering TValidationSummary-specific presentation. + * @return string the rendering result + */ + public function renderContents($writer) + { + $this->renderJsSummary(); + if($this->getShowSummary()) + { +// $this->setStyle('display:block'); + switch($this->getDisplayMode()) + { + case TValidationSummaryDisplayMode::SimpleList: + $this->renderList($writer); + break; + case TValidationSummaryDisplayMode::SingleParagraph: + $this->renderSingleParagraph($writer); + break; + case TValidationSummaryDisplayMode::BulletList: + $this->renderBulletList($writer); + break; + case TValidationSummaryDisplayMode::HeaderOnly: + $this->renderHeaderOnly($writer); + break; + } + } + } + + /** + * Render the validation summary as a simple list. + * @param array list of messages + * @param string the header text + * @return string summary list + */ + protected function renderList($writer) + { + $header=$this->getHeaderText(); + $messages=$this->getErrorMessages(); + $content = ''; + if(strlen($header)) + $content.= $header."<br/>\n"; + foreach($messages as $message) + $content.="$message<br/>\n"; + $writer->write($content); + } + + /** + * Render the validation summary as a paragraph. + * @param array list of messages + * @param string the header text + * @return string summary paragraph + */ + protected function renderSingleParagraph($writer) + { + $header=$this->getHeaderText(); + $messages=$this->getErrorMessages(); + $content = $header; + foreach($messages as $message) + $content.= ' '.$message; + $writer->write($content); + } + + /** + * Render the validation summary as a bullet list. + * @param array list of messages + * @param string the header text + * @return string summary bullet list + */ + protected function renderBulletList($writer) + { + $header=$this->getHeaderText(); + $messages=$this->getErrorMessages(); + $content = $header; + if(count($messages)>0) + { + $content .= "<ul>\n"; + foreach($messages as $message) + $content.= '<li>'.$message."</li>\n"; + $content .= "</ul>\n"; + } + $writer->write($content); + } + + /** + * Render the validation summary header text only. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function renderHeaderOnly($writer) + { + $writer->write($this->getHeaderText()); + } +} + +/** + * TClientSideValidationSummaryOptions class. + * + * Client-side validation summary events such as {@link setOnHideSummary + * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified + * through the {@link TBaseValidator:: getClientSide ClientSide} property of a + * validation summary. + * + * The <tt>OnHideSummary</tt> event is raise when the validation summary + * requests to hide the messages. + * + * The <tt>OnShowSummary</tt> event is raised when the validation summary + * requests to show the messages. + * + * See the quickstart documentation for further details. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TClientSideValidationSummaryOptions extends TClientSideOptions +{ + /** + * @return string javascript code for client-side OnHideSummary event. + */ + public function getOnHideSummary() + { + return $this->getOption('OnHideSummary'); + } + + /** + * Client-side OnHideSummary validation summary event is raise when all the + * validators are valid. This will override the default client-side + * validation summary behaviour. + * @param string javascript code for client-side OnHideSummary event. + */ + public function setOnHideSummary($javascript) + { + $this->setFunction('OnHideSummary', $javascript); + } + + /** + * Client-side OnShowSummary event is raise when one or more validators are + * not valid. This will override the default client-side validation summary + * behaviour. + * @param string javascript code for client-side OnShowSummary event. + */ + public function setOnShowSummary($javascript) + { + $this->setFunction('OnShowSummary', $javascript); + } + + /** + * @return string javascript code for client-side OnShowSummary event. + */ + public function getOnShowSummary() + { + return $this->getOption('OnShowSummary'); + } + + /** + * Ensure the string is a valid javascript function. The code block + * is enclosed with "function(summary, validators){ }" block. + * @param string javascript code. + * @return string javascript function code. + */ + protected function ensureFunction($javascript) + { + return "function(summary, validators){ {$javascript} }"; + } +} + + +/** + * TValidationSummaryDisplayMode class. + * TValidationSummaryDisplayMode defines the enumerable type for the possible modes + * that a {@link TValidationSummary} can organize and display the collected error messages. + * + * The following enumerable values are defined: + * - SimpleList: the error messages are displayed as a list without any decorations. + * - SingleParagraph: the error messages are concatenated together into a paragraph. + * - BulletList: the error messages are displayed as a bulleted list. + * - HeaderOnly: only the HeaderText will be display. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidationSummaryDisplayMode extends TEnumerable +{ + const SimpleList='SimpleList'; + const SingleParagraph='SingleParagraph'; + const BulletList='BulletList'; + const HeaderOnly='HeaderOnly'; +} + + +/** + * TValidationSummaryDisplay class. + * TValidationSummaryDisplay defines the enumerable type for the possible styles + * that a {@link TValidationSummary} can display the collected error messages. + * + * The following enumerable values are defined: + * - None: the error messages are not displayed + * - Dynamic: the error messages are dynamically added to display as the corresponding validators fail + * - Fixed: Similar to Dynamic except that the error messages physically occupy the page layout (even though they may not be visible) + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TValidationSummaryDisplayStyle extends TEnumerable +{ + const None='None'; + const Dynamic='Dynamic'; + const Fixed='Fixed'; +} + diff --git a/framework/Web/UI/WebControls/TWebControlAdapter.php b/framework/Web/UI/WebControls/TWebControlAdapter.php index 68fecf1c..ad1e1642 100644 --- a/framework/Web/UI/WebControls/TWebControlAdapter.php +++ b/framework/Web/UI/WebControls/TWebControlAdapter.php @@ -1,71 +1,71 @@ -<?php
-/**
- * TWebControlAdapter class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TWebControlAdapter class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TWebControlAdapter class
- *
- * TWebControlAdapter is the base class for adapters that customize
- * rendering for the Web control to which the adapter is attached.
- * It may be used to modify the default markup or behavior for specific
- * browsers.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWebControlAdapter extends TControlAdapter
-{
- /**
- * Renders the control to which the adapter is attached.
- * It calls {@link renderBeginTag}, {@link renderContents} and
- * {@link renderEndTag} in order.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- $this->renderBeginTag($writer);
- $this->renderContents($writer);
- $this->renderEndTag($writer);
- }
-
- /**
- * Renders the openning tag for the attached control.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- $this->getControl()->renderBeginTag($writer);
- }
-
- /**
- * Renders the body contents within the attached control tag.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderContents($writer)
- {
- $this->getControl()->renderContents($writer);
- }
-
- /**
- * Renders the closing tag for the attached control.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- $this->getControl()->renderEndTag($writer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +/** + * TWebControlAdapter class + * + * TWebControlAdapter is the base class for adapters that customize + * rendering for the Web control to which the adapter is attached. + * It may be used to modify the default markup or behavior for specific + * browsers. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWebControlAdapter extends TControlAdapter +{ + /** + * Renders the control to which the adapter is attached. + * It calls {@link renderBeginTag}, {@link renderContents} and + * {@link renderEndTag} in order. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + $this->renderBeginTag($writer); + $this->renderContents($writer); + $this->renderEndTag($writer); + } + + /** + * Renders the openning tag for the attached control. + * Default implementation calls the attached control's corresponding method. + * @param THtmlWriter writer for the rendering purpose + */ + public function renderBeginTag($writer) + { + $this->getControl()->renderBeginTag($writer); + } + + /** + * Renders the body contents within the attached control tag. + * Default implementation calls the attached control's corresponding method. + * @param THtmlWriter writer for the rendering purpose + */ + public function renderContents($writer) + { + $this->getControl()->renderContents($writer); + } + + /** + * Renders the closing tag for the attached control. + * Default implementation calls the attached control's corresponding method. + * @param THtmlWriter writer for the rendering purpose + */ + public function renderEndTag($writer) + { + $this->getControl()->renderEndTag($writer); + } +} + diff --git a/framework/Web/UI/WebControls/TWizard.php b/framework/Web/UI/WebControls/TWizard.php index 25d3a41b..b497d719 100644 --- a/framework/Web/UI/WebControls/TWizard.php +++ b/framework/Web/UI/WebControls/TWizard.php @@ -1,1402 +1,1402 @@ -<?php
-/**
- * TWizard and the relevant class definitions.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TWizard and the relevant class definitions. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TMultiView');
-Prado::using('System.Web.UI.WebControls.TPanel');
-Prado::using('System.Web.UI.WebControls.TButton');
-Prado::using('System.Web.UI.WebControls.TLinkButton');
-Prado::using('System.Web.UI.WebControls.TImageButton');
-Prado::using('System.Web.UI.WebControls.TDataList');
-Prado::using('System.Web.UI.WebControls.TWizardNavigationButtonStyle');
-
-/**
- * Class TWizard.
- *
- * TWizard splits a large form and presents the user with a series of smaller
- * forms to complete. TWizard is analogous to the installation wizard commonly
- * used to install software in Windows.
- *
- * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via
- * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added
- * into a wizard using the following syntax,
- * <code>
- * <com:TWizard>
- * <com:TWizardStep Title="step 1">
- * content in step 1, may contain other controls
- * </com:TWizardStep>
- * <com:TWizardStep Title="step 2">
- * content in step 2, may contain other controls
- * </com:TWizardStep>
- * </com:TWizard>
- * </code>
- *
- * Each wizard step can be one of the following types:
- * - Start : the first step in the wizard.
- * - Step : the internal steps in the wizard.
- * - Finish : the last step that allows user interaction.
- * - Complete : the step that shows a summary to user (no interaction is allowed).
- * - Auto : the step type is determined by wizard automatically.
- * At any time, only one step is visible to end-users, which can be obtained
- * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by
- * {@link getActiveStepIndex ActiveStepIndex}.
- *
- * Wizard content can be customized in many ways.
- *
- * The layout of a wizard consists of four parts: header, step content, navigation
- * and side bar. Their content are affected by the following properties, respectively,
- * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}.
- * If both are present, the latter takes precedence.
- * - step: {@link getWizardSteps WizardSteps}.
- * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate},
- * {@link setStepNavigationTemplate StepNavigationTemplate},
- * {@link setFinishNavigationTemplate FinishNavigationTemplate}.
- * Default templates will be used if above templates are not set.
- * - side bar: {@link setSideBarTemplate SideBarTemplate}.
- * A default template will be used if this template is not set.
- * Its visibility is toggled by {@link setShowSideBar ShowSideBar}.
- *
- * The style of these wizard layout components can be customized via the following style properties,
- * - header: {@link getHeaderStyle HeaderStyle}.
- * - step: {@link getStepStyle StepStyle}.
- * - navigation: {@link getNavigationStyle NavigationStyle},
- * {@link getStartNextButtonStyle StartNextButtonStyle},
- * {@link getStepNextButtonStyle StepNextButtonStyle},
- * {@link getStepPreviousButtonStyle StepPreviousButtonStyle},
- * {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle},
- * {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle},
- * {@link getCancelButtonStyle CancelButtonStyle}.
- * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizard extends TWebControl implements INamingContainer
-{
- /**
- * Wizard step types.
- * @deprecated deprecated since version 3.0.4 (use TWizardStepType constants instead)
- */
- const ST_AUTO='Auto';
- const ST_START='Start';
- const ST_STEP='Step';
- const ST_FINISH='Finish';
- const ST_COMPLETE='Complete';
- /**
- * Navigation commands.
- */
- const CMD_PREVIOUS='PreviousStep';
- const CMD_NEXT='NextStep';
- const CMD_CANCEL='Cancel';
- const CMD_COMPLETE='Complete';
- const CMD_MOVETO='MoveTo';
- /**
- * Side bar button ID
- */
- const ID_SIDEBAR_BUTTON='SideBarButton';
- /**
- * Side bar data list
- */
- const ID_SIDEBAR_LIST='SideBarList';
-
- /**
- * @var TMultiView multiview that contains the wizard steps
- */
- private $_multiView=null;
- /**
- * @var mixed navigation template for the start step.
- */
- private $_startNavigationTemplate=null;
- /**
- * @var mixed navigation template for internal steps.
- */
- private $_stepNavigationTemplate=null;
- /**
- * @var mixed navigation template for the finish step.
- */
- private $_finishNavigationTemplate=null;
- /**
- * @var mixed template for wizard header.
- */
- private $_headerTemplate=null;
- /**
- * @var mixed template for the side bar.
- */
- private $_sideBarTemplate=null;
- /**
- * @var TWizardStepCollection
- */
- private $_wizardSteps=null;
- /**
- * @var TPanel container of the wizard header
- */
- private $_header;
- /**
- * @var TPanel container of the wizard step content
- */
- private $_stepContent;
- /**
- * @var TPanel container of the wizard side bar
- */
- private $_sideBar;
- /**
- * @var TPanel navigation panel
- */
- private $_navigation;
- /**
- * @var TWizardNavigationContainer container of the start navigation
- */
- private $_startNavigation;
- /**
- * @var TWizardNavigationContainer container of the step navigation
- */
- private $_stepNavigation;
- /**
- * @var TWizardNavigationContainer container of the finish navigation
- */
- private $_finishNavigation;
- /**
- * @var boolean whether ActiveStepIndex was already set
- */
- private $_activeStepIndexSet=false;
- /**
- * @var TDataList side bar data list.
- */
- private $_sideBarDataList;
- /**
- * @var boolean whether navigation should be cancelled (a status set in OnSideBarButtonClick)
- */
- private $_cancelNavigation=false;
-
- /**
- * @return string tag name for the wizard
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds {@link TWizardStep} objects into step collection.
- * This method overrides the parent implementation and is
- * invoked when template is being instantiated.
- * @param mixed object instantiated in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TWizardStep)
- $this->getWizardSteps()->add($object);
- }
-
- /**
- * @return TWizardStep the currently active wizard step
- */
- public function getActiveStep()
- {
- return $this->getMultiView()->getActiveView();
- }
-
- /**
- * @param TWizardStep step to be activated
- * @throws TInvalidOperationException if the step is not in the wizard step collection
- */
- public function setActiveStep($step)
- {
- if(($index=$this->getWizardSteps()->indexOf($step))<0)
- throw new TInvalidOperationException('wizard_step_invalid');
- $this->setActiveStepIndex($index);
- }
-
- /**
- * @return integer the zero-based index of the active wizard step
- */
- public function getActiveStepIndex()
- {
- return $this->getMultiView()->getActiveViewIndex();
- }
-
- /**
- * @param integer the zero-based index of the wizard step to be activated
- */
- public function setActiveStepIndex($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- $multiView=$this->getMultiView();
- if($multiView->getActiveViewIndex()!==$value)
- {
- $multiView->setActiveViewIndex($value);
- $this->_activeStepIndexSet=true;
- if($this->_sideBarDataList!==null && $this->getSideBarTemplate()!==null)
- {
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
- }
-
- /**
- * @return TWizardStepCollection collection of wizard steps
- */
- public function getWizardSteps()
- {
- if($this->_wizardSteps===null)
- $this->_wizardSteps=new TWizardStepCollection($this);
- return $this->_wizardSteps;
- }
-
- /**
- * @return boolean whether to display a cancel button in each wizard step. Defaults to false.
- */
- public function getShowCancelButton()
- {
- return $this->getViewState('ShowCancelButton',false);
- }
-
- /**
- * @param boolean whether to display a cancel button in each wizard step.
- */
- public function setShowCancelButton($value)
- {
- $this->setViewState('ShowCancelButton',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether to display a side bar that contains links to wizard steps. Defaults to true.
- */
- public function getShowSideBar()
- {
- return $this->getViewState('ShowSideBar',true);
- }
-
- /**
- * @param boolean whether to display a side bar that contains links to wizard steps.
- */
- public function setShowSideBar($value)
- {
- $this->setViewState('ShowSideBar',TPropertyValue::ensureBoolean($value),true);
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for the start step. Defaults to null.
- */
- public function getStartNavigationTemplate()
- {
- return $this->_startNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for the start step.
- */
- public function setStartNavigationTemplate($value)
- {
- $this->_startNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for internal steps. Defaults to null.
- */
- public function getStepNavigationTemplate()
- {
- return $this->_stepNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for internal steps.
- */
- public function setStepNavigationTemplate($value)
- {
- $this->_stepNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for the finish step. Defaults to null.
- */
- public function getFinishNavigationTemplate()
- {
- return $this->_finishNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for the finish step.
- */
- public function setFinishNavigationTemplate($value)
- {
- $this->_finishNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate template for wizard header. Defaults to null.
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate template for wizard header.
- */
- public function setHeaderTemplate($value)
- {
- $this->_headerTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate template for the side bar. Defaults to null.
- */
- public function getSideBarTemplate()
- {
- return $this->_sideBarTemplate;
- }
-
- /**
- * @param ITemplate template for the side bar.
- */
- public function setSideBarTemplate($value)
- {
- $this->_sideBarTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return string header text. Defaults to ''.
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * @param string header text.
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL that the browser will be redirected to if the cancel button in the
- * wizard is clicked. Defaults to ''.
- */
- public function getCancelDestinationUrl()
- {
- return $this->getViewState('CancelDestinationUrl','');
- }
-
- /**
- * @param string the URL that the browser will be redirected to if the cancel button in the
- * wizard is clicked.
- */
- public function setCancelDestinationUrl($value)
- {
- $this->setViewState('CancelDestinationUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL that the browser will be redirected to if the wizard finishes.
- * Defaults to ''.
- */
- public function getFinishDestinationUrl()
- {
- return $this->getViewState('FinishDestinationUrl','');
- }
-
- /**
- * @param string the URL that the browser will be redirected to if the wizard finishes.
- */
- public function setFinishDestinationUrl($value)
- {
- $this->setViewState('FinishDestinationUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return TStyle the style for the buttons displayed in the side bar.
- */
- public function getSideBarButtonStyle()
- {
- if(($style=$this->getViewState('SideBarButtonStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('SideBarButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style common for all navigation buttons.
- */
- public function getNavigationButtonStyle()
- {
- if(($style=$this->getViewState('NavigationButtonStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('NavigationButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step.
- */
- public function getStartNextButtonStyle()
- {
- if(($style=$this->getViewState('StartNextButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Next');
- $this->setViewState('StartNextButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step.
- */
- public function getStepNextButtonStyle()
- {
- if(($style=$this->getViewState('StepNextButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Next');
- $this->setViewState('StepNextButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
- */
- public function getStepPreviousButtonStyle()
- {
- if(($style=$this->getViewState('StepPreviousButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Previous');
- $this->setViewState('StepPreviousButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step.
- */
- public function getFinishCompleteButtonStyle()
- {
- if(($style=$this->getViewState('FinishCompleteButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Complete');
- $this->setViewState('FinishCompleteButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
- */
- public function getFinishPreviousButtonStyle()
- {
- if(($style=$this->getViewState('FinishPreviousButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Previous');
- $this->setViewState('FinishPreviousButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the cancel button
- */
- public function getCancelButtonStyle()
- {
- if(($style=$this->getViewState('CancelButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Cancel');
- $this->setViewState('CancelButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the side bar.
- */
- public function getSideBarStyle()
- {
- if(($style=$this->getViewState('SideBarStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('SideBarStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the header.
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for each internal wizard step.
- */
- public function getStepStyle()
- {
- if(($style=$this->getViewState('StepStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('StepStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the navigation panel.
- */
- public function getNavigationStyle()
- {
- if(($style=$this->getViewState('NavigationStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('NavigationStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return boolean whether to use default layout to arrange side bar and the rest wizard components. Defaults to true.
- */
- public function getUseDefaultLayout()
- {
- return $this->getViewState('UseDefaultLayout',true);
- }
-
- /**
- * @param boolean whether to use default layout to arrange side bar and the rest wizard components.
- * If true, an HTML table will be used which places the side bar in the left cell
- * while the rest components in the right cell.
- */
- public function setUseDefaultLayout($value)
- {
- $this->setViewState('UseDefaultLayout',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TPanel container of the wizard header
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TPanel container of the wizard step content
- */
- public function getStepContent()
- {
- return $this->_stepContent;
- }
-
- /**
- * @return TPanel container of the wizard side bar
- */
- public function getSideBar()
- {
- return $this->_sideBar;
- }
-
- /**
- * @return TWizardNavigationContainer container of the start navigation
- */
- public function getStartNavigation()
- {
- return $this->_startNavigation;
- }
-
- /**
- * @return TWizardNavigationContainer container of the step navigation
- */
- public function getStepNavigation()
- {
- return $this->_stepNavigation;
- }
-
- /**
- * @return TWizardNavigationContainer container of the finish navigation
- */
- public function getFinishNavigation()
- {
- return $this->_finishNavigation;
- }
-
- /**
- * Raises <b>OnActiveStepChanged</b> event.
- * This event is raised when the current visible step is changed in the
- * wizard.
- * @param TEventParameter event parameter
- */
- public function onActiveStepChanged($param)
- {
- $this->raiseEvent('OnActiveStepChanged',$this,$param);
- }
-
- /**
- * Raises <b>OnCancelButtonClick</b> event.
- * This event is raised when a cancel navigation button is clicked in the
- * current active step.
- * @param TEventParameter event parameter
- */
- public function onCancelButtonClick($param)
- {
- $this->raiseEvent('OnCancelButtonClick',$this,$param);
- if(($url=$this->getCancelDestinationUrl())!=='')
- $this->getResponse()->redirect($url);
- }
-
- /**
- * Raises <b>OnCompleteButtonClick</b> event.
- * This event is raised when a finish navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onCompleteButtonClick($param)
- {
- $this->raiseEvent('OnCompleteButtonClick',$this,$param);
- if(($url=$this->getFinishDestinationUrl())!=='')
- $this->getResponse()->redirect($url);
- }
-
- /**
- * Raises <b>OnNextButtonClick</b> event.
- * This event is raised when a next navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onNextButtonClick($param)
- {
- $this->raiseEvent('OnNextButtonClick',$this,$param);
- }
-
- /**
- * Raises <b>OnPreviousButtonClick</b> event.
- * This event is raised when a previous navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onPreviousButtonClick($param)
- {
- $this->raiseEvent('OnPreviousButtonClick',$this,$param);
- }
-
- /**
- * Raises <b>OnSideBarButtonClick</b> event.
- * This event is raised when a link button in the side bar is clicked.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onSideBarButtonClick($param)
- {
- $this->raiseEvent('OnSideBarButtonClick',$this,$param);
- }
-
- /**
- * Returns the multiview that holds the wizard steps.
- * This method should only be used by control developers.
- * @return TMultiView the multiview holding wizard steps
- */
- public function getMultiView()
- {
- if($this->_multiView===null)
- {
- $this->_multiView=new TMultiView;
- $this->_multiView->setID('WizardMultiView');
- $this->_multiView->attachEventHandler('OnActiveViewChanged',array($this,'onActiveStepChanged'));
- $this->_multiView->ignoreBubbleEvents();
- }
- return $this->_multiView;
- }
-
- /**
- * Adds a wizard step to the multiview.
- * This method should only be used by control developers.
- * It is invoked when a step is added into the step collection of the wizard.
- * @param TWizardStep wizard step to be added into multiview.
- */
- public function addedWizardStep($step)
- {
- if(($wizard=$step->getWizard())!==null)
- $wizard->getWizardSteps()->remove($step);
- $step->setWizard($this);
- $this->wizardStepsChanged();
- }
-
- /**
- * Removes a wizard step from the multiview.
- * This method should only be used by control developers.
- * It is invoked when a step is removed from the step collection of the wizard.
- * @param TWizardStep wizard step to be removed from multiview.
- */
- public function removedWizardStep($step)
- {
- $step->setWizard(null);
- $this->wizardStepsChanged();
- }
-
- /**
- * Creates the child controls of the wizard.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->ensureChildControls();
- if($this->getActiveStepIndex()<0 && $this->getWizardSteps()->getCount()>0)
- $this->setActiveStepIndex(0);
- }
-
- /**
- * Saves the current active step index into history.
- * This method is invoked by the framework when the control state is being saved.
- */
- public function saveState()
- {
- $index=$this->getActiveStepIndex();
- $history=$this->getHistory();
- if(!$history->getCount() || $history->peek()!==$index)
- $history->push($index);
- }
-
- /**
- * Indicates the wizard needs to recreate all child controls.
- */
- protected function requiresControlsRecreation()
- {
- if($this->getChildControlsCreated())
- $this->setChildControlsCreated(false);
- }
-
- /**
- * Renders the wizard.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- $this->ensureChildControls();
- if($this->getHasControls())
- {
- if($this->getUseDefaultLayout())
- {
- $this->applyControlProperties();
- $this->renderBeginTag($writer);
- $writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n");
- $this->_sideBar->renderControl($writer);
- $writer->write("\n</td><td valign=\"top\">\n");
- $this->_header->renderControl($writer);
- $this->_stepContent->renderControl($writer);
- $this->_navigation->renderControl($writer);
- $writer->write("\n</td></tr></table>\n");
- $this->renderEndTag($writer);
- }
- else
- {
- $this->applyControlProperties();
- $this->renderBeginTag($writer);
- $this->_sideBar->renderControl($writer);
- $this->_header->renderControl($writer);
- $this->_stepContent->renderControl($writer);
- $this->_navigation->renderControl($writer);
- $this->renderEndTag($writer);
- }
- }
- }
-
- /**
- * Applies various properties to the components of wizard
- */
- protected function applyControlProperties()
- {
- $this->applyHeaderProperties();
- $this->applySideBarProperties();
- $this->applyStepContentProperties();
- $this->applyNavigationProperties();
- }
-
- /**
- * Applies properties to the wizard header
- */
- protected function applyHeaderProperties()
- {
- if(($style=$this->getViewState('HeaderStyle',null))!==null)
- $this->_header->getStyle()->mergeWith($style);
- if($this->getHeaderTemplate()===null)
- {
- $this->_header->getControls()->clear();
- $this->_header->getControls()->add($this->getHeaderText());
- }
- }
-
- /**
- * Applies properties to the wizard sidebar
- */
- protected function applySideBarProperties()
- {
- $this->_sideBar->setVisible($this->getShowSideBar());
- if($this->_sideBarDataList!==null && $this->getShowSideBar())
- {
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- if(($style=$this->getViewState('SideBarButtonStyle',null))!==null)
- {
- foreach($this->_sideBarDataList->getItems() as $item)
- {
- if(($button=$item->findControl('SideBarButton'))!==null)
- $button->getStyle()->mergeWith($style);
- }
- }
- }
- if(($style=$this->getViewState('SideBarStyle',null))!==null)
- $this->_sideBar->getStyle()->mergeWith($style);
- }
-
- /**
- * Applies properties to the wizard step content
- */
- protected function applyStepContentProperties()
- {
- if(($style=$this->getViewState('StepStyle',null))!==null)
- $this->_stepContent->getStyle()->mergeWith($style);
- }
-
- /**
- * Apply properties to various navigation panels.
- */
- protected function applyNavigationProperties()
- {
- $wizardSteps=$this->getWizardSteps();
- $activeStep=$this->getActiveStep();
- $activeStepIndex=$this->getActiveStepIndex();
-
- if(!$this->_navigation)
- return;
- else if($activeStepIndex<0 || $activeStepIndex>=$wizardSteps->getCount())
- {
- $this->_navigation->setVisible(false);
- return;
- }
-
- // set visibility of different types of navigation panel
- $showStandard=true;
- foreach($wizardSteps as $step)
- {
- if(($step instanceof TTemplatedWizardStep) && ($container=$step->getNavigationContainer())!==null)
- {
- if($activeStep===$step)
- {
- $container->setVisible(true);
- $showStandard=false;
- }
- else
- $container->setVisible(false);
- }
- }
- $activeStepType=$this->getStepType($activeStep);
- if($activeStepType===TWizardStepType::Complete)
- {
- $this->_sideBar->setVisible(false);
- $this->_header->setVisible(false);
- }
- $this->_startNavigation->setVisible($showStandard && $activeStepType===self::ST_START);
- $this->_stepNavigation->setVisible($showStandard && $activeStepType===self::ST_STEP);
- $this->_finishNavigation->setVisible($showStandard && $activeStepType===self::ST_FINISH);
-
- if(($navigationStyle=$this->getViewState('NavigationStyle',null))!==null)
- $this->_navigation->getStyle()->mergeWith($navigationStyle);
-
- $displayCancelButton=$this->getShowCancelButton();
- $cancelButtonStyle=$this->getCancelButtonStyle();
- $buttonStyle=$this->getViewState('NavigationButtonStyle',null);
- if($buttonStyle!==null)
- $cancelButtonStyle->mergeWith($buttonStyle);
-
- // apply styles to start navigation buttons
- if(($cancelButton=$this->_startNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_startNavigation->getNextButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getStartNextButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Start)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
-
- // apply styles to finish navigation buttons
- if(($cancelButton=$this->_finishNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_finishNavigation->getPreviousButton())!==null)
- {
- $button->setVisible($this->allowNavigationToPreviousStep());
- $style=$this->getFinishPreviousButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- }
- if(($button=$this->_finishNavigation->getCompleteButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getFinishCompleteButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Finish)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
-
- // apply styles to step navigation buttons
- if(($cancelButton=$this->_stepNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_stepNavigation->getPreviousButton())!==null)
- {
- $button->setVisible($this->allowNavigationToPreviousStep());
- $style=$this->getStepPreviousButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- }
- if(($button=$this->_stepNavigation->getNextButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getStepNextButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Step)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
- }
-
- /**
- * @return TStack history containing step indexes that were navigated before
- */
- protected function getHistory()
- {
- if(($history=$this->getControlState('History',null))===null)
- {
- $history=new TStack;
- $this->setControlState('History',$history);
- }
- return $history;
- }
-
- /**
- * Determines the type of the specified wizard step.
- * @param TWizardStep
- * @return TWizardStepType type of the step
- */
- protected function getStepType($wizardStep)
- {
- if(($type=$wizardStep->getStepType())===TWizardStepType::Auto)
- {
- $steps=$this->getWizardSteps();
- if(($index=$steps->indexOf($wizardStep))>=0)
- {
- $stepCount=$steps->getCount();
- if($stepCount===1 || ($index<$stepCount-1 && $steps->itemAt($index+1)->getStepType()===TWizardStepType::Complete))
- return TWizardStepType::Finish;
- else if($index===0)
- return TWizardStepType::Start;
- else if($index===$stepCount-1)
- return TWizardStepType::Finish;
- else
- return TWizardStepType::Step;
- }
- else
- return $type;
- }
- else
- return $type;
- }
-
- /**
- * Clears up everything within the wizard.
- */
- protected function reset()
- {
- $this->getControls()->clear();
- $this->_header=null;
- $this->_stepContent=null;
- $this->_sideBar=null;
- $this->_sideBarDataList=null;
- $this->_navigation=null;
- $this->_startNavigation=null;
- $this->_stepNavigation=null;
- $this->_finishNavigation=null;
- }
-
- /**
- * Creates child controls within the wizard
- */
- public function createChildControls()
- {
- $this->reset();
- $this->createSideBar();
- $this->createHeader();
- $this->createStepContent();
- $this->createNavigation();
-// $this->clearChildState();
- }
-
- /**
- * Creates the wizard header.
- */
- protected function createHeader()
- {
- $this->_header=new TPanel;
- if(($template=$this->getHeaderTemplate())!==null)
- $template->instantiateIn($this->_header);
- else
- $this->_header->getControls()->add($this->getHeaderText());
- $this->getControls()->add($this->_header);
- }
-
- /**
- * Creates the wizard side bar
- */
- protected function createSideBar()
- {
- if($this->getShowSideBar())
- {
- if(($template=$this->getSideBarTemplate())===null)
- $template=new TWizardSideBarTemplate;
- $this->_sideBar=new TPanel;
- $template->instantiateIn($this->_sideBar);
- $this->getControls()->add($this->_sideBar);
-
- if(($this->_sideBarDataList=$this->_sideBar->findControl(self::ID_SIDEBAR_LIST))!==null)
- {
- $this->_sideBarDataList->attachEventHandler('OnItemCommand',array($this,'dataListItemCommand'));
- $this->_sideBarDataList->attachEventHandler('OnItemDataBound',array($this,'dataListItemDataBound'));
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
- else
- {
- $this->_sideBar=new TPanel;
- $this->getControls()->add($this->_sideBar);
- }
- }
-
- /**
- * Event handler for sidebar datalist's OnItemCommand event.
- * This method is used internally by wizard. It mainly
- * sets the active step index according to the button clicked in the sidebar.
- * @param mixed sender of the event
- * @param TDataListCommandEventParameter
- */
- public function dataListItemCommand($sender,$param)
- {
- $item=$param->getItem();
- if($param->getCommandName()===self::CMD_MOVETO)
- {
- $stepIndex=$this->getActiveStepIndex();
- $newStepIndex=TPropertyValue::ensureInteger($param->getCommandParameter());
- $navParam=new TWizardNavigationEventParameter($stepIndex);
- $navParam->setNextStepIndex($newStepIndex);
-
- // if the button clicked causes validation which fails,
- // by default we will cancel navigation to the new step
- $button=$param->getCommandSource();
- if(($button instanceof IButtonControl) && $button->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
- $navParam->setCancelNavigation(true);
-
- $this->_activeStepIndexSet=false;
- $this->onSideBarButtonClick($navParam);
- $this->_cancelNavigation=$navParam->getCancelNavigation();
- if(!$this->_cancelNavigation)
- {
- if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex))
- $this->setActiveStepIndex($newStepIndex);
- }
- else
- $this->setActiveStepIndex($stepIndex);
- }
- }
-
- /**
- * Event handler for sidebar datalist's OnItemDataBound event.
- * This method is used internally by wizard. It mainly configures
- * the buttons in the sidebar datalist.
- * @param mixed sender of the event
- * @param TDataListItemEventParameter
- */
- public function dataListItemDataBound($sender,$param)
- {
- $item=$param->getItem();
- $itemType=$item->getItemType();
- if($itemType==='Item' || $itemType==='AlternatingItem' || $itemType==='SelectedItem' || $itemType==='EditItem')
- {
- if(($button=$item->findControl(self::ID_SIDEBAR_BUTTON))!==null)
- {
- $step=$item->getData();
- if(($this->getStepType($step)===TWizardStepType::Complete))
- $button->setEnabled(false);
- if(($title=$step->getTitle())!=='')
- $button->setText($title);
- else
- $button->setText($step->getID(false));
- $index=$this->getWizardSteps()->indexOf($step);
- $button->setCommandName(self::CMD_MOVETO);
- $button->setCommandParameter("$index");
- }
- }
- }
-
- /**
- * Creates wizard step content.
- */
- protected function createStepContent()
- {
- foreach($this->getWizardSteps() as $step)
- {
- if($step instanceof TTemplatedWizardStep)
- $step->ensureChildControls();
- }
- $multiView=$this->getMultiView();
- $this->_stepContent=new TPanel;
- $this->_stepContent->getControls()->add($multiView);
- $this->getControls()->add($this->_stepContent);
- if($multiView->getViews()->getCount())
- $multiView->setActiveViewIndex(0);
- }
-
- /**
- * Creates navigation panel.
- */
- protected function createNavigation()
- {
- $this->_navigation=new TPanel;
- $this->getControls()->add($this->_navigation);
- $controls=$this->_navigation->getControls();
- foreach($this->getWizardSteps() as $step)
- {
- if($step instanceof TTemplatedWizardStep)
- {
- $step->instantiateNavigationTemplate();
- if(($panel=$step->getNavigationContainer())!==null)
- $controls->add($panel);
- }
- }
- $this->_startNavigation=$this->createStartNavigation();
- $controls->add($this->_startNavigation);
- $this->_stepNavigation=$this->createStepNavigation();
- $controls->add($this->_stepNavigation);
- $this->_finishNavigation=$this->createFinishNavigation();
- $controls->add($this->_finishNavigation);
- }
-
- /**
- * Creates start navigation panel.
- */
- protected function createStartNavigation()
- {
- if(($template=$this->getStartNavigationTemplate())===null)
- $template=new TWizardStartNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Creates step navigation panel.
- */
- protected function createStepNavigation()
- {
- if(($template=$this->getStepNavigationTemplate())===null)
- $template=new TWizardStepNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Creates finish navigation panel.
- */
- protected function createFinishNavigation()
- {
- if(($template=$this->getFinishNavigationTemplate())===null)
- $template=new TWizardFinishNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Updates the sidebar datalist if any.
- * This method is invoked when any wizard step is changed.
- */
- public function wizardStepsChanged()
- {
- if($this->_sideBarDataList!==null)
- {
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
-
- /**
- * Determines the index of the previous step based on history.
- * @param boolean whether the first item in the history stack should be popped
- * up after calling this method.
- */
- protected function getPreviousStepIndex($popStack)
- {
- $history=$this->getHistory();
- if($history->getCount()>=0)
- {
- $activeStepIndex=$this->getActiveStepIndex();
- $previousStepIndex=-1;
- if($popStack)
- {
- $previousStepIndex=$history->pop();
- if($activeStepIndex===$previousStepIndex && $history->getCount()>0)
- $previousStepIndex=$history->pop();
- }
- else
- {
- $previousStepIndex=$history->peek();
- if($activeStepIndex===$previousStepIndex && $history->getCount()>1)
- {
- $saveIndex=$history->pop();
- $previousStepIndex=$history->peek();
- $history->push($saveIndex);
- }
- }
- return $activeStepIndex===$previousStepIndex ? -1 : $previousStepIndex;
- }
- else
- return -1;
- }
-
- /**
- * @return boolean whether navigation to the previous step is allowed
- */
- protected function allowNavigationToPreviousStep()
- {
- if(($index=$this->getPreviousStepIndex(false))!==-1)
- return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
- else
- return false;
- }
-
- /**
- * @param integer index of the step
- * @return boolean whether navigation to the specified step is allowed
- */
- protected function allowNavigationToStep($index)
- {
- if($this->getHistory()->contains($index))
- return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
- else
- return true;
- }
-
- /**
- * Handles bubbled events.
- * This method mainly translate certain command events into
- * wizard-specific events.
- * @param mixed sender of the original command event
- * @param TEventParameter event parameter
- * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelButtonClick($param);
- return true;
- }
-
- $type=$this->getStepType($this->getActiveStep());
- $index=$this->getActiveStepIndex();
- $navParam=new TWizardNavigationEventParameter($index);
- if(($sender instanceof IButtonControl) && $sender->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
- $navParam->setCancelNavigation(true);
-
- $handled=false;
- $movePrev=false;
- $this->_activeStepIndexSet=false;
-
- if(strcasecmp($command,self::CMD_NEXT)===0)
- {
- if($type!==self::ST_START && $type!==self::ST_STEP)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_NEXT);
- if($index<$this->getWizardSteps()->getCount()-1)
- $navParam->setNextStepIndex($index+1);
- $this->onNextButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_PREVIOUS)===0)
- {
- if($type!==self::ST_FINISH && $type!==self::ST_STEP)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_PREVIOUS);
- $movePrev=true;
- if(($prevIndex=$this->getPreviousStepIndex(false))>=0)
- $navParam->setNextStepIndex($prevIndex);
- $this->onPreviousButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_COMPLETE)===0)
- {
- if($type!==self::ST_FINISH)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_COMPLETE);
- if($index<$this->getWizardSteps()->getCount()-1)
- $navParam->setNextStepIndex($index+1);
- $this->onCompleteButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_MOVETO)===0)
- {
- if($this->_cancelNavigation) // may be set in onSideBarButtonClick
+ * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls + */ + +Prado::using('System.Web.UI.WebControls.TMultiView'); +Prado::using('System.Web.UI.WebControls.TPanel'); +Prado::using('System.Web.UI.WebControls.TButton'); +Prado::using('System.Web.UI.WebControls.TLinkButton'); +Prado::using('System.Web.UI.WebControls.TImageButton'); +Prado::using('System.Web.UI.WebControls.TDataList'); +Prado::using('System.Web.UI.WebControls.TWizardNavigationButtonStyle'); + +/** + * Class TWizard. + * + * TWizard splits a large form and presents the user with a series of smaller + * forms to complete. TWizard is analogous to the installation wizard commonly + * used to install software in Windows. + * + * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via + * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added + * into a wizard using the following syntax, + * <code> + * <com:TWizard> + * <com:TWizardStep Title="step 1"> + * content in step 1, may contain other controls + * </com:TWizardStep> + * <com:TWizardStep Title="step 2"> + * content in step 2, may contain other controls + * </com:TWizardStep> + * </com:TWizard> + * </code> + * + * Each wizard step can be one of the following types: + * - Start : the first step in the wizard. + * - Step : the internal steps in the wizard. + * - Finish : the last step that allows user interaction. + * - Complete : the step that shows a summary to user (no interaction is allowed). + * - Auto : the step type is determined by wizard automatically. + * At any time, only one step is visible to end-users, which can be obtained + * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by + * {@link getActiveStepIndex ActiveStepIndex}. + * + * Wizard content can be customized in many ways. + * + * The layout of a wizard consists of four parts: header, step content, navigation + * and side bar. Their content are affected by the following properties, respectively, + * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}. + * If both are present, the latter takes precedence. + * - step: {@link getWizardSteps WizardSteps}. + * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate}, + * {@link setStepNavigationTemplate StepNavigationTemplate}, + * {@link setFinishNavigationTemplate FinishNavigationTemplate}. + * Default templates will be used if above templates are not set. + * - side bar: {@link setSideBarTemplate SideBarTemplate}. + * A default template will be used if this template is not set. + * Its visibility is toggled by {@link setShowSideBar ShowSideBar}. + * + * The style of these wizard layout components can be customized via the following style properties, + * - header: {@link getHeaderStyle HeaderStyle}. + * - step: {@link getStepStyle StepStyle}. + * - navigation: {@link getNavigationStyle NavigationStyle}, + * {@link getStartNextButtonStyle StartNextButtonStyle}, + * {@link getStepNextButtonStyle StepNextButtonStyle}, + * {@link getStepPreviousButtonStyle StepPreviousButtonStyle}, + * {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle}, + * {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle}, + * {@link getCancelButtonStyle CancelButtonStyle}. + * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizard extends TWebControl implements INamingContainer +{ + /** + * Wizard step types. + * @deprecated deprecated since version 3.0.4 (use TWizardStepType constants instead) + */ + const ST_AUTO='Auto'; + const ST_START='Start'; + const ST_STEP='Step'; + const ST_FINISH='Finish'; + const ST_COMPLETE='Complete'; + /** + * Navigation commands. + */ + const CMD_PREVIOUS='PreviousStep'; + const CMD_NEXT='NextStep'; + const CMD_CANCEL='Cancel'; + const CMD_COMPLETE='Complete'; + const CMD_MOVETO='MoveTo'; + /** + * Side bar button ID + */ + const ID_SIDEBAR_BUTTON='SideBarButton'; + /** + * Side bar data list + */ + const ID_SIDEBAR_LIST='SideBarList'; + + /** + * @var TMultiView multiview that contains the wizard steps + */ + private $_multiView=null; + /** + * @var mixed navigation template for the start step. + */ + private $_startNavigationTemplate=null; + /** + * @var mixed navigation template for internal steps. + */ + private $_stepNavigationTemplate=null; + /** + * @var mixed navigation template for the finish step. + */ + private $_finishNavigationTemplate=null; + /** + * @var mixed template for wizard header. + */ + private $_headerTemplate=null; + /** + * @var mixed template for the side bar. + */ + private $_sideBarTemplate=null; + /** + * @var TWizardStepCollection + */ + private $_wizardSteps=null; + /** + * @var TPanel container of the wizard header + */ + private $_header; + /** + * @var TPanel container of the wizard step content + */ + private $_stepContent; + /** + * @var TPanel container of the wizard side bar + */ + private $_sideBar; + /** + * @var TPanel navigation panel + */ + private $_navigation; + /** + * @var TWizardNavigationContainer container of the start navigation + */ + private $_startNavigation; + /** + * @var TWizardNavigationContainer container of the step navigation + */ + private $_stepNavigation; + /** + * @var TWizardNavigationContainer container of the finish navigation + */ + private $_finishNavigation; + /** + * @var boolean whether ActiveStepIndex was already set + */ + private $_activeStepIndexSet=false; + /** + * @var TDataList side bar data list. + */ + private $_sideBarDataList; + /** + * @var boolean whether navigation should be cancelled (a status set in OnSideBarButtonClick) + */ + private $_cancelNavigation=false; + + /** + * @return string tag name for the wizard + */ + protected function getTagName() + { + return 'div'; + } + + /** + * Adds {@link TWizardStep} objects into step collection. + * This method overrides the parent implementation and is + * invoked when template is being instantiated. + * @param mixed object instantiated in template + */ + public function addParsedObject($object) + { + if($object instanceof TWizardStep) + $this->getWizardSteps()->add($object); + } + + /** + * @return TWizardStep the currently active wizard step + */ + public function getActiveStep() + { + return $this->getMultiView()->getActiveView(); + } + + /** + * @param TWizardStep step to be activated + * @throws TInvalidOperationException if the step is not in the wizard step collection + */ + public function setActiveStep($step) + { + if(($index=$this->getWizardSteps()->indexOf($step))<0) + throw new TInvalidOperationException('wizard_step_invalid'); + $this->setActiveStepIndex($index); + } + + /** + * @return integer the zero-based index of the active wizard step + */ + public function getActiveStepIndex() + { + return $this->getMultiView()->getActiveViewIndex(); + } + + /** + * @param integer the zero-based index of the wizard step to be activated + */ + public function setActiveStepIndex($value) + { + $value=TPropertyValue::ensureInteger($value); + $multiView=$this->getMultiView(); + if($multiView->getActiveViewIndex()!==$value) + { + $multiView->setActiveViewIndex($value); + $this->_activeStepIndexSet=true; + if($this->_sideBarDataList!==null && $this->getSideBarTemplate()!==null) + { + $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex()); + $this->_sideBarDataList->dataBind(); + } + } + } + + /** + * @return TWizardStepCollection collection of wizard steps + */ + public function getWizardSteps() + { + if($this->_wizardSteps===null) + $this->_wizardSteps=new TWizardStepCollection($this); + return $this->_wizardSteps; + } + + /** + * @return boolean whether to display a cancel button in each wizard step. Defaults to false. + */ + public function getShowCancelButton() + { + return $this->getViewState('ShowCancelButton',false); + } + + /** + * @param boolean whether to display a cancel button in each wizard step. + */ + public function setShowCancelButton($value) + { + $this->setViewState('ShowCancelButton',TPropertyValue::ensureBoolean($value),false); + } + + /** + * @return boolean whether to display a side bar that contains links to wizard steps. Defaults to true. + */ + public function getShowSideBar() + { + return $this->getViewState('ShowSideBar',true); + } + + /** + * @param boolean whether to display a side bar that contains links to wizard steps. + */ + public function setShowSideBar($value) + { + $this->setViewState('ShowSideBar',TPropertyValue::ensureBoolean($value),true); + $this->requiresControlsRecreation(); + } + + /** + * @return ITemplate navigation template for the start step. Defaults to null. + */ + public function getStartNavigationTemplate() + { + return $this->_startNavigationTemplate; + } + + /** + * @param ITemplate navigation template for the start step. + */ + public function setStartNavigationTemplate($value) + { + $this->_startNavigationTemplate=$value; + $this->requiresControlsRecreation(); + } + + /** + * @return ITemplate navigation template for internal steps. Defaults to null. + */ + public function getStepNavigationTemplate() + { + return $this->_stepNavigationTemplate; + } + + /** + * @param ITemplate navigation template for internal steps. + */ + public function setStepNavigationTemplate($value) + { + $this->_stepNavigationTemplate=$value; + $this->requiresControlsRecreation(); + } + + /** + * @return ITemplate navigation template for the finish step. Defaults to null. + */ + public function getFinishNavigationTemplate() + { + return $this->_finishNavigationTemplate; + } + + /** + * @param ITemplate navigation template for the finish step. + */ + public function setFinishNavigationTemplate($value) + { + $this->_finishNavigationTemplate=$value; + $this->requiresControlsRecreation(); + } + + /** + * @return ITemplate template for wizard header. Defaults to null. + */ + public function getHeaderTemplate() + { + return $this->_headerTemplate; + } + + /** + * @param ITemplate template for wizard header. + */ + public function setHeaderTemplate($value) + { + $this->_headerTemplate=$value; + $this->requiresControlsRecreation(); + } + + /** + * @return ITemplate template for the side bar. Defaults to null. + */ + public function getSideBarTemplate() + { + return $this->_sideBarTemplate; + } + + /** + * @param ITemplate template for the side bar. + */ + public function setSideBarTemplate($value) + { + $this->_sideBarTemplate=$value; + $this->requiresControlsRecreation(); + } + + /** + * @return string header text. Defaults to ''. + */ + public function getHeaderText() + { + return $this->getViewState('HeaderText',''); + } + + /** + * @param string header text. + */ + public function setHeaderText($value) + { + $this->setViewState('HeaderText',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the URL that the browser will be redirected to if the cancel button in the + * wizard is clicked. Defaults to ''. + */ + public function getCancelDestinationUrl() + { + return $this->getViewState('CancelDestinationUrl',''); + } + + /** + * @param string the URL that the browser will be redirected to if the cancel button in the + * wizard is clicked. + */ + public function setCancelDestinationUrl($value) + { + $this->setViewState('CancelDestinationUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return string the URL that the browser will be redirected to if the wizard finishes. + * Defaults to ''. + */ + public function getFinishDestinationUrl() + { + return $this->getViewState('FinishDestinationUrl',''); + } + + /** + * @param string the URL that the browser will be redirected to if the wizard finishes. + */ + public function setFinishDestinationUrl($value) + { + $this->setViewState('FinishDestinationUrl',TPropertyValue::ensureString($value),''); + } + + /** + * @return TStyle the style for the buttons displayed in the side bar. + */ + public function getSideBarButtonStyle() + { + if(($style=$this->getViewState('SideBarButtonStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('SideBarButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TStyle the style common for all navigation buttons. + */ + public function getNavigationButtonStyle() + { + if(($style=$this->getViewState('NavigationButtonStyle',null))===null) + { + $style=new TStyle; + $this->setViewState('NavigationButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step. + */ + public function getStartNextButtonStyle() + { + if(($style=$this->getViewState('StartNextButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Next'); + $this->setViewState('StartNextButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step. + */ + public function getStepNextButtonStyle() + { + if(($style=$this->getViewState('StepNextButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Next'); + $this->setViewState('StepNextButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step. + */ + public function getStepPreviousButtonStyle() + { + if(($style=$this->getViewState('StepPreviousButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Previous'); + $this->setViewState('StepPreviousButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step. + */ + public function getFinishCompleteButtonStyle() + { + if(($style=$this->getViewState('FinishCompleteButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Complete'); + $this->setViewState('FinishCompleteButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step. + */ + public function getFinishPreviousButtonStyle() + { + if(($style=$this->getViewState('FinishPreviousButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Previous'); + $this->setViewState('FinishPreviousButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TWizardNavigationButtonStyle the style for the cancel button + */ + public function getCancelButtonStyle() + { + if(($style=$this->getViewState('CancelButtonStyle',null))===null) + { + $style=new TWizardNavigationButtonStyle; + $style->setButtonText('Cancel'); + $this->setViewState('CancelButtonStyle',$style,null); + } + return $style; + } + + /** + * @return TPanelStyle the style for the side bar. + */ + public function getSideBarStyle() + { + if(($style=$this->getViewState('SideBarStyle',null))===null) + { + $style=new TPanelStyle; + $this->setViewState('SideBarStyle',$style,null); + } + return $style; + } + + /** + * @return TPanelStyle the style for the header. + */ + public function getHeaderStyle() + { + if(($style=$this->getViewState('HeaderStyle',null))===null) + { + $style=new TPanelStyle; + $this->setViewState('HeaderStyle',$style,null); + } + return $style; + } + + /** + * @return TPanelStyle the style for each internal wizard step. + */ + public function getStepStyle() + { + if(($style=$this->getViewState('StepStyle',null))===null) + { + $style=new TPanelStyle; + $this->setViewState('StepStyle',$style,null); + } + return $style; + } + + /** + * @return TPanelStyle the style for the navigation panel. + */ + public function getNavigationStyle() + { + if(($style=$this->getViewState('NavigationStyle',null))===null) + { + $style=new TPanelStyle; + $this->setViewState('NavigationStyle',$style,null); + } + return $style; + } + + /** + * @return boolean whether to use default layout to arrange side bar and the rest wizard components. Defaults to true. + */ + public function getUseDefaultLayout() + { + return $this->getViewState('UseDefaultLayout',true); + } + + /** + * @param boolean whether to use default layout to arrange side bar and the rest wizard components. + * If true, an HTML table will be used which places the side bar in the left cell + * while the rest components in the right cell. + */ + public function setUseDefaultLayout($value) + { + $this->setViewState('UseDefaultLayout',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return TPanel container of the wizard header + */ + public function getHeader() + { + return $this->_header; + } + + /** + * @return TPanel container of the wizard step content + */ + public function getStepContent() + { + return $this->_stepContent; + } + + /** + * @return TPanel container of the wizard side bar + */ + public function getSideBar() + { + return $this->_sideBar; + } + + /** + * @return TWizardNavigationContainer container of the start navigation + */ + public function getStartNavigation() + { + return $this->_startNavigation; + } + + /** + * @return TWizardNavigationContainer container of the step navigation + */ + public function getStepNavigation() + { + return $this->_stepNavigation; + } + + /** + * @return TWizardNavigationContainer container of the finish navigation + */ + public function getFinishNavigation() + { + return $this->_finishNavigation; + } + + /** + * Raises <b>OnActiveStepChanged</b> event. + * This event is raised when the current visible step is changed in the + * wizard. + * @param TEventParameter event parameter + */ + public function onActiveStepChanged($param) + { + $this->raiseEvent('OnActiveStepChanged',$this,$param); + } + + /** + * Raises <b>OnCancelButtonClick</b> event. + * This event is raised when a cancel navigation button is clicked in the + * current active step. + * @param TEventParameter event parameter + */ + public function onCancelButtonClick($param) + { + $this->raiseEvent('OnCancelButtonClick',$this,$param); + if(($url=$this->getCancelDestinationUrl())!=='') + $this->getResponse()->redirect($url); + } + + /** + * Raises <b>OnCompleteButtonClick</b> event. + * This event is raised when a finish navigation button is clicked in the + * current active step. + * @param TWizardNavigationEventParameter event parameter + */ + public function onCompleteButtonClick($param) + { + $this->raiseEvent('OnCompleteButtonClick',$this,$param); + if(($url=$this->getFinishDestinationUrl())!=='') + $this->getResponse()->redirect($url); + } + + /** + * Raises <b>OnNextButtonClick</b> event. + * This event is raised when a next navigation button is clicked in the + * current active step. + * @param TWizardNavigationEventParameter event parameter + */ + public function onNextButtonClick($param) + { + $this->raiseEvent('OnNextButtonClick',$this,$param); + } + + /** + * Raises <b>OnPreviousButtonClick</b> event. + * This event is raised when a previous navigation button is clicked in the + * current active step. + * @param TWizardNavigationEventParameter event parameter + */ + public function onPreviousButtonClick($param) + { + $this->raiseEvent('OnPreviousButtonClick',$this,$param); + } + + /** + * Raises <b>OnSideBarButtonClick</b> event. + * This event is raised when a link button in the side bar is clicked. + * @param TWizardNavigationEventParameter event parameter + */ + public function onSideBarButtonClick($param) + { + $this->raiseEvent('OnSideBarButtonClick',$this,$param); + } + + /** + * Returns the multiview that holds the wizard steps. + * This method should only be used by control developers. + * @return TMultiView the multiview holding wizard steps + */ + public function getMultiView() + { + if($this->_multiView===null) + { + $this->_multiView=new TMultiView; + $this->_multiView->setID('WizardMultiView'); + $this->_multiView->attachEventHandler('OnActiveViewChanged',array($this,'onActiveStepChanged')); + $this->_multiView->ignoreBubbleEvents(); + } + return $this->_multiView; + } + + /** + * Adds a wizard step to the multiview. + * This method should only be used by control developers. + * It is invoked when a step is added into the step collection of the wizard. + * @param TWizardStep wizard step to be added into multiview. + */ + public function addedWizardStep($step) + { + if(($wizard=$step->getWizard())!==null) + $wizard->getWizardSteps()->remove($step); + $step->setWizard($this); + $this->wizardStepsChanged(); + } + + /** + * Removes a wizard step from the multiview. + * This method should only be used by control developers. + * It is invoked when a step is removed from the step collection of the wizard. + * @param TWizardStep wizard step to be removed from multiview. + */ + public function removedWizardStep($step) + { + $step->setWizard(null); + $this->wizardStepsChanged(); + } + + /** + * Creates the child controls of the wizard. + * This method overrides the parent implementation. + * @param TEventParameter event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $this->ensureChildControls(); + if($this->getActiveStepIndex()<0 && $this->getWizardSteps()->getCount()>0) + $this->setActiveStepIndex(0); + } + + /** + * Saves the current active step index into history. + * This method is invoked by the framework when the control state is being saved. + */ + public function saveState() + { + $index=$this->getActiveStepIndex(); + $history=$this->getHistory(); + if(!$history->getCount() || $history->peek()!==$index) + $history->push($index); + } + + /** + * Indicates the wizard needs to recreate all child controls. + */ + protected function requiresControlsRecreation() + { + if($this->getChildControlsCreated()) + $this->setChildControlsCreated(false); + } + + /** + * Renders the wizard. + * @param THtmlWriter + */ + public function render($writer) + { + $this->ensureChildControls(); + if($this->getHasControls()) + { + if($this->getUseDefaultLayout()) + { + $this->applyControlProperties(); + $this->renderBeginTag($writer); + $writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n"); + $this->_sideBar->renderControl($writer); + $writer->write("\n</td><td valign=\"top\">\n"); + $this->_header->renderControl($writer); + $this->_stepContent->renderControl($writer); + $this->_navigation->renderControl($writer); + $writer->write("\n</td></tr></table>\n"); + $this->renderEndTag($writer); + } + else + { + $this->applyControlProperties(); + $this->renderBeginTag($writer); + $this->_sideBar->renderControl($writer); + $this->_header->renderControl($writer); + $this->_stepContent->renderControl($writer); + $this->_navigation->renderControl($writer); + $this->renderEndTag($writer); + } + } + } + + /** + * Applies various properties to the components of wizard + */ + protected function applyControlProperties() + { + $this->applyHeaderProperties(); + $this->applySideBarProperties(); + $this->applyStepContentProperties(); + $this->applyNavigationProperties(); + } + + /** + * Applies properties to the wizard header + */ + protected function applyHeaderProperties() + { + if(($style=$this->getViewState('HeaderStyle',null))!==null) + $this->_header->getStyle()->mergeWith($style); + if($this->getHeaderTemplate()===null) + { + $this->_header->getControls()->clear(); + $this->_header->getControls()->add($this->getHeaderText()); + } + } + + /** + * Applies properties to the wizard sidebar + */ + protected function applySideBarProperties() + { + $this->_sideBar->setVisible($this->getShowSideBar()); + if($this->_sideBarDataList!==null && $this->getShowSideBar()) + { + $this->_sideBarDataList->setDataSource($this->getWizardSteps()); + $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex()); + $this->_sideBarDataList->dataBind(); + if(($style=$this->getViewState('SideBarButtonStyle',null))!==null) + { + foreach($this->_sideBarDataList->getItems() as $item) + { + if(($button=$item->findControl('SideBarButton'))!==null) + $button->getStyle()->mergeWith($style); + } + } + } + if(($style=$this->getViewState('SideBarStyle',null))!==null) + $this->_sideBar->getStyle()->mergeWith($style); + } + + /** + * Applies properties to the wizard step content + */ + protected function applyStepContentProperties() + { + if(($style=$this->getViewState('StepStyle',null))!==null) + $this->_stepContent->getStyle()->mergeWith($style); + } + + /** + * Apply properties to various navigation panels. + */ + protected function applyNavigationProperties() + { + $wizardSteps=$this->getWizardSteps(); + $activeStep=$this->getActiveStep(); + $activeStepIndex=$this->getActiveStepIndex(); + + if(!$this->_navigation) + return; + else if($activeStepIndex<0 || $activeStepIndex>=$wizardSteps->getCount()) + { + $this->_navigation->setVisible(false); + return; + } + + // set visibility of different types of navigation panel + $showStandard=true; + foreach($wizardSteps as $step) + { + if(($step instanceof TTemplatedWizardStep) && ($container=$step->getNavigationContainer())!==null) + { + if($activeStep===$step) + { + $container->setVisible(true); + $showStandard=false; + } + else + $container->setVisible(false); + } + } + $activeStepType=$this->getStepType($activeStep); + if($activeStepType===TWizardStepType::Complete) + { + $this->_sideBar->setVisible(false); + $this->_header->setVisible(false); + } + $this->_startNavigation->setVisible($showStandard && $activeStepType===self::ST_START); + $this->_stepNavigation->setVisible($showStandard && $activeStepType===self::ST_STEP); + $this->_finishNavigation->setVisible($showStandard && $activeStepType===self::ST_FINISH); + + if(($navigationStyle=$this->getViewState('NavigationStyle',null))!==null) + $this->_navigation->getStyle()->mergeWith($navigationStyle); + + $displayCancelButton=$this->getShowCancelButton(); + $cancelButtonStyle=$this->getCancelButtonStyle(); + $buttonStyle=$this->getViewState('NavigationButtonStyle',null); + if($buttonStyle!==null) + $cancelButtonStyle->mergeWith($buttonStyle); + + // apply styles to start navigation buttons + if(($cancelButton=$this->_startNavigation->getCancelButton())!==null) + { + $cancelButton->setVisible($displayCancelButton); + $cancelButtonStyle->apply($cancelButton); + } + if(($button=$this->_startNavigation->getNextButton())!==null) + { + $button->setVisible(true); + $style=$this->getStartNextButtonStyle(); + if($buttonStyle!==null) + $style->mergeWith($buttonStyle); + $style->apply($button); + if($activeStepType===TWizardStepType::Start) + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + } + + // apply styles to finish navigation buttons + if(($cancelButton=$this->_finishNavigation->getCancelButton())!==null) + { + $cancelButton->setVisible($displayCancelButton); + $cancelButtonStyle->apply($cancelButton); + } + if(($button=$this->_finishNavigation->getPreviousButton())!==null) + { + $button->setVisible($this->allowNavigationToPreviousStep()); + $style=$this->getFinishPreviousButtonStyle(); + if($buttonStyle!==null) + $style->mergeWith($buttonStyle); + $style->apply($button); + } + if(($button=$this->_finishNavigation->getCompleteButton())!==null) + { + $button->setVisible(true); + $style=$this->getFinishCompleteButtonStyle(); + if($buttonStyle!==null) + $style->mergeWith($buttonStyle); + $style->apply($button); + if($activeStepType===TWizardStepType::Finish) + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + } + + // apply styles to step navigation buttons + if(($cancelButton=$this->_stepNavigation->getCancelButton())!==null) + { + $cancelButton->setVisible($displayCancelButton); + $cancelButtonStyle->apply($cancelButton); + } + if(($button=$this->_stepNavigation->getPreviousButton())!==null) + { + $button->setVisible($this->allowNavigationToPreviousStep()); + $style=$this->getStepPreviousButtonStyle(); + if($buttonStyle!==null) + $style->mergeWith($buttonStyle); + $style->apply($button); + } + if(($button=$this->_stepNavigation->getNextButton())!==null) + { + $button->setVisible(true); + $style=$this->getStepNextButtonStyle(); + if($buttonStyle!==null) + $style->mergeWith($buttonStyle); + $style->apply($button); + if($activeStepType===TWizardStepType::Step) + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + } + } + + /** + * @return TStack history containing step indexes that were navigated before + */ + protected function getHistory() + { + if(($history=$this->getControlState('History',null))===null) + { + $history=new TStack; + $this->setControlState('History',$history); + } + return $history; + } + + /** + * Determines the type of the specified wizard step. + * @param TWizardStep + * @return TWizardStepType type of the step + */ + protected function getStepType($wizardStep) + { + if(($type=$wizardStep->getStepType())===TWizardStepType::Auto) + { + $steps=$this->getWizardSteps(); + if(($index=$steps->indexOf($wizardStep))>=0) + { + $stepCount=$steps->getCount(); + if($stepCount===1 || ($index<$stepCount-1 && $steps->itemAt($index+1)->getStepType()===TWizardStepType::Complete)) + return TWizardStepType::Finish; + else if($index===0) + return TWizardStepType::Start; + else if($index===$stepCount-1) + return TWizardStepType::Finish; + else + return TWizardStepType::Step; + } + else + return $type; + } + else + return $type; + } + + /** + * Clears up everything within the wizard. + */ + protected function reset() + { + $this->getControls()->clear(); + $this->_header=null; + $this->_stepContent=null; + $this->_sideBar=null; + $this->_sideBarDataList=null; + $this->_navigation=null; + $this->_startNavigation=null; + $this->_stepNavigation=null; + $this->_finishNavigation=null; + } + + /** + * Creates child controls within the wizard + */ + public function createChildControls() + { + $this->reset(); + $this->createSideBar(); + $this->createHeader(); + $this->createStepContent(); + $this->createNavigation(); +// $this->clearChildState(); + } + + /** + * Creates the wizard header. + */ + protected function createHeader() + { + $this->_header=new TPanel; + if(($template=$this->getHeaderTemplate())!==null) + $template->instantiateIn($this->_header); + else + $this->_header->getControls()->add($this->getHeaderText()); + $this->getControls()->add($this->_header); + } + + /** + * Creates the wizard side bar + */ + protected function createSideBar() + { + if($this->getShowSideBar()) + { + if(($template=$this->getSideBarTemplate())===null) + $template=new TWizardSideBarTemplate; + $this->_sideBar=new TPanel; + $template->instantiateIn($this->_sideBar); + $this->getControls()->add($this->_sideBar); + + if(($this->_sideBarDataList=$this->_sideBar->findControl(self::ID_SIDEBAR_LIST))!==null) + { + $this->_sideBarDataList->attachEventHandler('OnItemCommand',array($this,'dataListItemCommand')); + $this->_sideBarDataList->attachEventHandler('OnItemDataBound',array($this,'dataListItemDataBound')); + $this->_sideBarDataList->setDataSource($this->getWizardSteps()); + $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex()); + $this->_sideBarDataList->dataBind(); + } + } + else + { + $this->_sideBar=new TPanel; + $this->getControls()->add($this->_sideBar); + } + } + + /** + * Event handler for sidebar datalist's OnItemCommand event. + * This method is used internally by wizard. It mainly + * sets the active step index according to the button clicked in the sidebar. + * @param mixed sender of the event + * @param TDataListCommandEventParameter + */ + public function dataListItemCommand($sender,$param) + { + $item=$param->getItem(); + if($param->getCommandName()===self::CMD_MOVETO) + { + $stepIndex=$this->getActiveStepIndex(); + $newStepIndex=TPropertyValue::ensureInteger($param->getCommandParameter()); + $navParam=new TWizardNavigationEventParameter($stepIndex); + $navParam->setNextStepIndex($newStepIndex); + + // if the button clicked causes validation which fails, + // by default we will cancel navigation to the new step + $button=$param->getCommandSource(); + if(($button instanceof IButtonControl) && $button->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid()) + $navParam->setCancelNavigation(true); + + $this->_activeStepIndexSet=false; + $this->onSideBarButtonClick($navParam); + $this->_cancelNavigation=$navParam->getCancelNavigation(); + if(!$this->_cancelNavigation) + { + if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex)) + $this->setActiveStepIndex($newStepIndex); + } + else + $this->setActiveStepIndex($stepIndex); + } + } + + /** + * Event handler for sidebar datalist's OnItemDataBound event. + * This method is used internally by wizard. It mainly configures + * the buttons in the sidebar datalist. + * @param mixed sender of the event + * @param TDataListItemEventParameter + */ + public function dataListItemDataBound($sender,$param) + { + $item=$param->getItem(); + $itemType=$item->getItemType(); + if($itemType==='Item' || $itemType==='AlternatingItem' || $itemType==='SelectedItem' || $itemType==='EditItem') + { + if(($button=$item->findControl(self::ID_SIDEBAR_BUTTON))!==null) + { + $step=$item->getData(); + if(($this->getStepType($step)===TWizardStepType::Complete)) + $button->setEnabled(false); + if(($title=$step->getTitle())!=='') + $button->setText($title); + else + $button->setText($step->getID(false)); + $index=$this->getWizardSteps()->indexOf($step); + $button->setCommandName(self::CMD_MOVETO); + $button->setCommandParameter("$index"); + } + } + } + + /** + * Creates wizard step content. + */ + protected function createStepContent() + { + foreach($this->getWizardSteps() as $step) + { + if($step instanceof TTemplatedWizardStep) + $step->ensureChildControls(); + } + $multiView=$this->getMultiView(); + $this->_stepContent=new TPanel; + $this->_stepContent->getControls()->add($multiView); + $this->getControls()->add($this->_stepContent); + if($multiView->getViews()->getCount()) + $multiView->setActiveViewIndex(0); + } + + /** + * Creates navigation panel. + */ + protected function createNavigation() + { + $this->_navigation=new TPanel; + $this->getControls()->add($this->_navigation); + $controls=$this->_navigation->getControls(); + foreach($this->getWizardSteps() as $step) + { + if($step instanceof TTemplatedWizardStep) + { + $step->instantiateNavigationTemplate(); + if(($panel=$step->getNavigationContainer())!==null) + $controls->add($panel); + } + } + $this->_startNavigation=$this->createStartNavigation(); + $controls->add($this->_startNavigation); + $this->_stepNavigation=$this->createStepNavigation(); + $controls->add($this->_stepNavigation); + $this->_finishNavigation=$this->createFinishNavigation(); + $controls->add($this->_finishNavigation); + } + + /** + * Creates start navigation panel. + */ + protected function createStartNavigation() + { + if(($template=$this->getStartNavigationTemplate())===null) + $template=new TWizardStartNavigationTemplate($this); + $navigation=new TWizardNavigationContainer; + $template->instantiateIn($navigation); + return $navigation; + } + + /** + * Creates step navigation panel. + */ + protected function createStepNavigation() + { + if(($template=$this->getStepNavigationTemplate())===null) + $template=new TWizardStepNavigationTemplate($this); + $navigation=new TWizardNavigationContainer; + $template->instantiateIn($navigation); + return $navigation; + } + + /** + * Creates finish navigation panel. + */ + protected function createFinishNavigation() + { + if(($template=$this->getFinishNavigationTemplate())===null) + $template=new TWizardFinishNavigationTemplate($this); + $navigation=new TWizardNavigationContainer; + $template->instantiateIn($navigation); + return $navigation; + } + + /** + * Updates the sidebar datalist if any. + * This method is invoked when any wizard step is changed. + */ + public function wizardStepsChanged() + { + if($this->_sideBarDataList!==null) + { + $this->_sideBarDataList->setDataSource($this->getWizardSteps()); + $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex()); + $this->_sideBarDataList->dataBind(); + } + } + + /** + * Determines the index of the previous step based on history. + * @param boolean whether the first item in the history stack should be popped + * up after calling this method. + */ + protected function getPreviousStepIndex($popStack) + { + $history=$this->getHistory(); + if($history->getCount()>=0) + { + $activeStepIndex=$this->getActiveStepIndex(); + $previousStepIndex=-1; + if($popStack) + { + $previousStepIndex=$history->pop(); + if($activeStepIndex===$previousStepIndex && $history->getCount()>0) + $previousStepIndex=$history->pop(); + } + else + { + $previousStepIndex=$history->peek(); + if($activeStepIndex===$previousStepIndex && $history->getCount()>1) + { + $saveIndex=$history->pop(); + $previousStepIndex=$history->peek(); + $history->push($saveIndex); + } + } + return $activeStepIndex===$previousStepIndex ? -1 : $previousStepIndex; + } + else + return -1; + } + + /** + * @return boolean whether navigation to the previous step is allowed + */ + protected function allowNavigationToPreviousStep() + { + if(($index=$this->getPreviousStepIndex(false))!==-1) + return $this->getWizardSteps()->itemAt($index)->getAllowReturn(); + else + return false; + } + + /** + * @param integer index of the step + * @return boolean whether navigation to the specified step is allowed + */ + protected function allowNavigationToStep($index) + { + if($this->getHistory()->contains($index)) + return $this->getWizardSteps()->itemAt($index)->getAllowReturn(); + else + return true; + } + + /** + * Handles bubbled events. + * This method mainly translate certain command events into + * wizard-specific events. + * @param mixed sender of the original command event + * @param TEventParameter event parameter + * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter + */ + public function bubbleEvent($sender,$param) + { + if($param instanceof TCommandEventParameter) + { + $command=$param->getCommandName(); + if(strcasecmp($command,self::CMD_CANCEL)===0) + { + $this->onCancelButtonClick($param); + return true; + } + + $type=$this->getStepType($this->getActiveStep()); + $index=$this->getActiveStepIndex(); + $navParam=new TWizardNavigationEventParameter($index); + if(($sender instanceof IButtonControl) && $sender->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid()) + $navParam->setCancelNavigation(true); + + $handled=false; + $movePrev=false; + $this->_activeStepIndexSet=false; + + if(strcasecmp($command,self::CMD_NEXT)===0) + { + if($type!==self::ST_START && $type!==self::ST_STEP) + throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_NEXT); + if($index<$this->getWizardSteps()->getCount()-1) + $navParam->setNextStepIndex($index+1); + $this->onNextButtonClick($navParam); + $handled=true; + } + else if(strcasecmp($command,self::CMD_PREVIOUS)===0) + { + if($type!==self::ST_FINISH && $type!==self::ST_STEP) + throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_PREVIOUS); + $movePrev=true; + if(($prevIndex=$this->getPreviousStepIndex(false))>=0) + $navParam->setNextStepIndex($prevIndex); + $this->onPreviousButtonClick($navParam); + $handled=true; + } + else if(strcasecmp($command,self::CMD_COMPLETE)===0) + { + if($type!==self::ST_FINISH) + throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_COMPLETE); + if($index<$this->getWizardSteps()->getCount()-1) + $navParam->setNextStepIndex($index+1); + $this->onCompleteButtonClick($navParam); + $handled=true; + } + else if(strcasecmp($command,self::CMD_MOVETO)===0) + { + if($this->_cancelNavigation) // may be set in onSideBarButtonClick $navParam->setCancelNavigation(true); $requestedStep=$param->getCommandParameter(); if (!is_numeric($requestedStep)) @@ -1412,750 +1412,750 @@ class TWizard extends TWebControl implements INamingContainer throw new TConfigurationException('wizard_step_invalid'); } else - $requestedIndex=TPropertyValue::ensureInteger($requestedStep);
- $navParam->setNextStepIndex($requestedIndex);
- $handled=true;
- }
-
- if($handled)
- {
- if(!$navParam->getCancelNavigation())
- {
- $nextStepIndex=$navParam->getNextStepIndex();
- if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex))
- {
- if($movePrev)
- $this->getPreviousStepIndex(true); // pop out the previous move from history
- $this->setActiveStepIndex($nextStepIndex);
- }
- }
- else
- $this->setActiveStepIndex($index);
- return true;
- }
- }
- return false;
- }
-}
-
-
-/**
- * TWizardStep class.
- *
- * TWizardStep represents a wizard step. The wizard owning the step
- * can be obtained by {@link getWizard Wizard}.
- * To specify the type of the step, set {@link setStepType StepType};
- * For step title, set {@link setTitle Title}. If a step can be re-visited,
- * set {@link setAllowReturn AllowReturn} to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStep extends TView
-{
- private $_wizard;
-
- /**
- * @return TWizard the wizard owning this step
- */
- public function getWizard()
- {
- return $this->_wizard;
- }
-
- /**
- * Sets the wizard owning this step.
- * This method is used internally by {@link TWizard}.
- * @param TWizard the wizard owning this step
- */
- public function setWizard($wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * @return string the title for this step.
- */
- public function getTitle()
- {
- return $this->getViewState('Title','');
- }
-
- /**
- * @param string the title for this step.
- */
- public function setTitle($value)
- {
- $this->setViewState('Title',$value,'');
- if($this->_wizard)
- $this->_wizard->wizardStepsChanged();
- }
-
- /**
- * @return boolean whether this step can be re-visited. Default to true.
- */
- public function getAllowReturn()
- {
- return $this->getViewState('AllowReturn',true);
- }
-
- /**
- * @param boolean whether this step can be re-visited.
- */
- public function setAllowReturn($value)
- {
- $this->setViewState('AllowReturn',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TWizardStepType the wizard step type. Defaults to TWizardStepType::Auto.
- */
- public function getStepType()
- {
- return $this->getViewState('StepType',TWizardStepType::Auto);
- }
-
- /**
- * @param TWizardStepType the wizard step type.
- */
- public function setStepType($type)
- {
- $type=TPropertyValue::ensureEnum($type,'TWizardStepType');
- if($type!==$this->getStepType())
- {
- $this->setViewState('StepType',$type,TWizardStepType::Auto);
- if($this->_wizard)
- $this->_wizard->wizardStepsChanged();
- }
- }
-}
-
-
-/**
- * TCompleteWizardStep class.
- *
- * TCompleteWizardStep represents a wizard step of type TWizardStepType::Complete.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCompleteWizardStep extends TWizardStep
-{
- /**
- * @return TWizardStepType the wizard step type. Always TWizardStepType::Complete.
- */
- public function getStepType()
- {
- return TWizardStepType::Complete;
- }
-
- /**
- * @param string the wizard step type.
- * @throws TInvalidOperationException whenever this method is invoked.
- */
- public function setStepType($value)
- {
- throw new TInvalidOperationException('completewizardstep_steptype_readonly');
- }
-}
-
-
-/**
- * TTemplatedWizardStep class.
- *
- * TTemplatedWizardStep represents a wizard step whose content and navigation
- * can be customized using templates. To customize the step content, specify
- * {@link setContentTemplate ContentTemplate}. To customize navigation specific
- * to the step, specify {@link setNavigationTemplate NavigationTemplate}. Note,
- * if the navigation template is not specified, default navigation will be used.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTemplatedWizardStep extends TWizardStep implements INamingContainer
-{
- /**
- * @var ITemplate the template for displaying the navigation UI of a wizard step.
- */
- private $_navigationTemplate=null;
- /**
- * @var ITemplate the template for displaying the content within the wizard step.
- */
- private $_contentTemplate=null;
- /**
- * @var TWizardNavigationContainer
- */
- private $_navigationContainer=null;
-
- /**
- * Creates child controls.
- * This method mainly instantiates the content template, if any.
- */
- public function createChildControls()
- {
- $this->getControls()->clear();
- if($this->_contentTemplate)
- $this->_contentTemplate->instantiateIn($this);
- }
-
- /**
- * Ensures child controls are created.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->ensureChildControls();
- }
-
- /**
- * @return ITemplate the template for the content of the wizard step.
- */
- public function getContentTemplate()
- {
- return $this->_contentTemplate;
- }
-
- /**
- * @param ITemplate the template for the content of the wizard step.
- */
- public function setContentTemplate($value)
- {
- $this->_contentTemplate=$value;
- }
-
- /**
- * @return ITemplate the template for displaying the navigation UI of a wizard step. Defaults to null.
- */
- public function getNavigationTemplate()
- {
- return $this->_navigationTemplate;
- }
-
- /**
- * @param ITemplate the template for displaying the navigation UI of a wizard step.
- */
- public function setNavigationTemplate($value)
- {
- $this->_navigationTemplate=$value;
- }
-
- /**
- * @return TWizardNavigationContainer the control containing the navigation.
- * It could be null if no navigation template is specified.
- */
- public function getNavigationContainer()
- {
- return $this->_navigationContainer;
- }
-
- /**
- * Instantiates the navigation template if any
- */
- public function instantiateNavigationTemplate()
- {
- if(!$this->_navigationContainer && $this->_navigationTemplate)
- {
- $this->_navigationContainer=new TWizardNavigationContainer;
- $this->_navigationTemplate->instantiateIn($this->_navigationContainer);
- }
- }
-}
-
-
-/**
- * TWizardStepCollection class.
- *
- * TWizardStepCollection represents the collection of wizard steps owned
- * by a {@link TWizard}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStepCollection extends TList
-{
- /**
- * @var TWizard
- */
- private $_wizard;
-
- /**
- * Constructor.
- * @param TWizard wizard that owns this collection
- */
- public function __construct(TWizard $wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * Inserts an item at the specified position.
- * This method overrides the parent implementation by checking if
- * the item being added is a {@link TWizardStep}.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item being added is not TWizardStep.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TWizardStep)
- {
- parent::insertAt($index,$item);
- $this->_wizard->getMultiView()->getViews()->insertAt($index,$item);
- $this->_wizard->addedWizardStep($item);
- }
- else
- throw new TInvalidDataTypeException('wizardstepcollection_wizardstep_required');
- }
-
- /**
- * Removes an item at the specified position.
- * @param integer the index of the item to be removed.
- * @return mixed the removed item.
- */
- public function removeAt($index)
- {
- $step=parent::removeAt($index);
- $this->_wizard->getMultiView()->getViews()->remove($step);
- $this->_wizard->removedWizardStep($step);
- return $step;
- }
-}
-
-
-/**
- * TWizardNavigationContainer class.
- *
- * TWizardNavigationContainer represents a control containing
- * a wizard navigation. The navigation may contain a few buttons, including
- * {@link getPreviousButton PreviousButton}, {@link getNextButton NextButton},
- * {@link getCancelButton CancelButton}, {@link getCompleteButton CompleteButton}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationContainer extends TControl implements INamingContainer
-{
- private $_previousButton=null;
- private $_nextButton=null;
- private $_cancelButton=null;
- private $_completeButton=null;
-
- /**
- * @return mixed the previous button
- */
- public function getPreviousButton()
- {
- return $this->_previousButton;
- }
-
- /**
- * @param mixed the previous button
- */
- public function setPreviousButton($value)
- {
- $this->_previousButton=$value;
- }
-
- /**
- * @return mixed the next button
- */
- public function getNextButton()
- {
- return $this->_nextButton;
- }
-
- /**
- * @param mixed the next button
- */
- public function setNextButton($value)
- {
- $this->_nextButton=$value;
- }
-
- /**
- * @return mixed the cancel button
- */
- public function getCancelButton()
- {
- return $this->_cancelButton;
- }
-
- /**
- * @param mixed the cancel button
- */
- public function setCancelButton($value)
- {
- $this->_cancelButton=$value;
- }
-
- /**
- * @return mixed the complete button
- */
- public function getCompleteButton()
- {
- return $this->_completeButton;
- }
-
- /**
- * @param mixed the complete button
- */
- public function setCompleteButton($value)
- {
- $this->_completeButton=$value;
- }
-}
-
-
-/**
- * TWizardNavigationEventParameter class.
- *
- * TWizardNavigationEventParameter represents the parameter for
- * {@link TWizard}'s navigation events.
- *
- * The index of the currently active step can be obtained from
- * {@link getCurrentStepIndex CurrentStepIndex}, while the index
- * of the candidate new step is in {@link getNextStepIndex NextStepIndex}.
- * By modifying {@link setNextStepIndex NextStepIndex}, the new step
- * can be changed to another one. If there is anything wrong with
- * the navigation and it is not wanted, set {@link setCancelNavigation CancelNavigation}
- * to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationEventParameter extends TEventParameter
-{
- private $_cancel=false;
- private $_currentStep;
- private $_nextStep;
-
- /**
- * Constructor.
- * @param integer current step index
- */
- public function __construct($currentStep)
- {
- $this->_currentStep=$currentStep;
- $this->_nextStep=$currentStep;
- }
-
- /**
- * @return integer the zero-based index of the currently active step.
- */
- public function getCurrentStepIndex()
- {
- return $this->_currentStep;
- }
-
- /**
- * @return integer the zero-based index of the next step. Default to {@link getCurrentStepIndex CurrentStepIndex}.
- */
- public function getNextStepIndex()
- {
- return $this->_nextStep;
- }
-
- /**
- * @param integer the zero-based index of the next step.
- */
- public function setNextStepIndex($index)
- {
- $this->_nextStep=TPropertyValue::ensureInteger($index);
- }
-
- /**
- * @return boolean whether navigation to the next step should be canceled. Default to false.
- */
- public function getCancelNavigation()
- {
- return $this->_cancel;
- }
-
- /**
- * @param boolean whether navigation to the next step should be canceled.
- */
- public function setCancelNavigation($value)
- {
- $this->_cancel=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * TWizardSideBarTemplate class.
- * TWizardSideBarTemplate is the default template for wizard sidebar.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardSideBarTemplate extends TComponent implements ITemplate
-{
- /**
- * Instantiates the template.
- * It creates a {@link TDataList} control.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $dataList=new TDataList;
- $dataList->setID(TWizard::ID_SIDEBAR_LIST);
- $dataList->getSelectedItemStyle()->getFont()->setBold(true);
- $dataList->setItemTemplate(new TWizardSideBarListItemTemplate);
- $parent->getControls()->add($dataList);
- }
-}
-
-/**
- * TWizardSideBarListItemTemplate class.
- * TWizardSideBarListItemTemplate is the default template for each item in the sidebar datalist.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardSideBarListItemTemplate extends TComponent implements ITemplate
-{
- /**
- * Instantiates the template.
- * It creates a {@link TLinkButton}.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $button=new TLinkButton;
- $button->setID(TWizard::ID_SIDEBAR_BUTTON);
- $parent->getControls()->add($button);
- }
-}
-
-/**
- * TWizardNavigationTemplate class.
- * TWizardNavigationTemplate is the base class for various navigation templates.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationTemplate extends TComponent implements ITemplate
-{
- private $_wizard;
-
- /**
- * Constructor.
- * @param TWizard the wizard owning this template
- */
- public function __construct($wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * @return TWizard the wizard owning this template
- */
- public function getWizard()
- {
- return $this->_wizard;
- }
-
- /**
- * Instantiates the template.
- * Derived classes should override this method.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- }
-
- /**
- * Creates a navigation button.
- * It creates a {@link TButton}, {@link TLinkButton}, or {@link TImageButton},
- * depending on the given parameters.
- * @param TWizardNavigationButtonStyle button style
- * @param boolean whether the button should cause validation
- * @param string command name for the button's OnCommand event
- * @throws TInvalidDataValueException if the button type is not recognized
- */
- protected function createNavigationButton($buttonStyle,$causesValidation,$commandName)
- {
- switch($buttonStyle->getButtonType())
- {
- case TWizardNavigationButtonType::Button:
- $button=new TButton;
- break;
- case TWizardNavigationButtonType::Link:
- $button=new TLinkButton;
- break;
- case TWizardNavigationButtonType::Image:
- $button=new TImageButton;
- $button->setImageUrl($buttonStyle->getImageUrl());
- break;
- default:
- throw new TInvalidDataValueException('wizard_buttontype_unknown',$buttonStyle->getButtonType());
- }
- $button->setText($buttonStyle->getButtonText());
- $button->setCausesValidation($causesValidation);
- $button->setCommandName($commandName);
- return $button;
- }
-}
-
-/**
- * TWizardStartNavigationTemplate class.
- * TWizardStartNavigationTemplate is the template used as default wizard start navigation panel.
- * It consists of two buttons, Next and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStartNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $nextButton=$this->createNavigationButton($this->getWizard()->getStartNextButtonStyle(),true,TWizard::CMD_NEXT);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($nextButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setNextButton($nextButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-/**
- * TWizardFinishNavigationTemplate class.
- * TWizardFinishNavigationTemplate is the template used as default wizard finish navigation panel.
- * It consists of three buttons, Previous, Complete and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardFinishNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $previousButton=$this->createNavigationButton($this->getWizard()->getFinishPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
- $completeButton=$this->createNavigationButton($this->getWizard()->getFinishCompleteButtonStyle(),true,TWizard::CMD_COMPLETE);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($previousButton);
- $controls->add("\n");
- $controls->add($completeButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setPreviousButton($previousButton);
- $parent->setCompleteButton($completeButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-/**
- * TWizardStepNavigationTemplate class.
- * TWizardStepNavigationTemplate is the template used as default wizard step navigation panel.
- * It consists of three buttons, Previous, Next and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStepNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $previousButton=$this->createNavigationButton($this->getWizard()->getStepPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
- $nextButton=$this->createNavigationButton($this->getWizard()->getStepNextButtonStyle(),true,TWizard::CMD_NEXT);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($previousButton);
- $controls->add("\n");
- $controls->add($nextButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setPreviousButton($previousButton);
- $parent->setNextButton($nextButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-
-/**
- * TWizardNavigationButtonType class.
- * TWizardNavigationButtonType defines the enumerable type for the possible types of buttons
- * that can be used in the navigation part of a {@link TWizard}.
- *
- * The following enumerable values are defined:
- * - Button: a regular click button
- * - Image: an image button
- * - Link: a hyperlink button
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TWizardNavigationButtonType extends TEnumerable
-{
- const Button='Button';
- const Image='Image';
- const Link='Link';
-}
-
-
-/**
- * TWizardStepType class.
- * TWizardStepType defines the enumerable type for the possible types of {@link TWizard wizard} steps.
- *
- * The following enumerable values are defined:
- * - Auto: the type is automatically determined based on the location of the wizard step in the whole step collection.
- * - Complete: the step is the last summary step.
- * - Start: the step is the first step
- * - Step: the step is between the begin and the end steps.
- * - Finish: the last step before the Complete step.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TWizardStepType extends TEnumerable
-{
- const Auto='Auto';
- const Complete='Complete';
- const Start='Start';
- const Step='Step';
- const Finish='Finish';
-}
-
+ $requestedIndex=TPropertyValue::ensureInteger($requestedStep); + $navParam->setNextStepIndex($requestedIndex); + $handled=true; + } + + if($handled) + { + if(!$navParam->getCancelNavigation()) + { + $nextStepIndex=$navParam->getNextStepIndex(); + if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex)) + { + if($movePrev) + $this->getPreviousStepIndex(true); // pop out the previous move from history + $this->setActiveStepIndex($nextStepIndex); + } + } + else + $this->setActiveStepIndex($index); + return true; + } + } + return false; + } +} + + +/** + * TWizardStep class. + * + * TWizardStep represents a wizard step. The wizard owning the step + * can be obtained by {@link getWizard Wizard}. + * To specify the type of the step, set {@link setStepType StepType}; + * For step title, set {@link setTitle Title}. If a step can be re-visited, + * set {@link setAllowReturn AllowReturn} to true. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardStep extends TView +{ + private $_wizard; + + /** + * @return TWizard the wizard owning this step + */ + public function getWizard() + { + return $this->_wizard; + } + + /** + * Sets the wizard owning this step. + * This method is used internally by {@link TWizard}. + * @param TWizard the wizard owning this step + */ + public function setWizard($wizard) + { + $this->_wizard=$wizard; + } + + /** + * @return string the title for this step. + */ + public function getTitle() + { + return $this->getViewState('Title',''); + } + + /** + * @param string the title for this step. + */ + public function setTitle($value) + { + $this->setViewState('Title',$value,''); + if($this->_wizard) + $this->_wizard->wizardStepsChanged(); + } + + /** + * @return boolean whether this step can be re-visited. Default to true. + */ + public function getAllowReturn() + { + return $this->getViewState('AllowReturn',true); + } + + /** + * @param boolean whether this step can be re-visited. + */ + public function setAllowReturn($value) + { + $this->setViewState('AllowReturn',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return TWizardStepType the wizard step type. Defaults to TWizardStepType::Auto. + */ + public function getStepType() + { + return $this->getViewState('StepType',TWizardStepType::Auto); + } + + /** + * @param TWizardStepType the wizard step type. + */ + public function setStepType($type) + { + $type=TPropertyValue::ensureEnum($type,'TWizardStepType'); + if($type!==$this->getStepType()) + { + $this->setViewState('StepType',$type,TWizardStepType::Auto); + if($this->_wizard) + $this->_wizard->wizardStepsChanged(); + } + } +} + + +/** + * TCompleteWizardStep class. + * + * TCompleteWizardStep represents a wizard step of type TWizardStepType::Complete. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TCompleteWizardStep extends TWizardStep +{ + /** + * @return TWizardStepType the wizard step type. Always TWizardStepType::Complete. + */ + public function getStepType() + { + return TWizardStepType::Complete; + } + + /** + * @param string the wizard step type. + * @throws TInvalidOperationException whenever this method is invoked. + */ + public function setStepType($value) + { + throw new TInvalidOperationException('completewizardstep_steptype_readonly'); + } +} + + +/** + * TTemplatedWizardStep class. + * + * TTemplatedWizardStep represents a wizard step whose content and navigation + * can be customized using templates. To customize the step content, specify + * {@link setContentTemplate ContentTemplate}. To customize navigation specific + * to the step, specify {@link setNavigationTemplate NavigationTemplate}. Note, + * if the navigation template is not specified, default navigation will be used. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TTemplatedWizardStep extends TWizardStep implements INamingContainer +{ + /** + * @var ITemplate the template for displaying the navigation UI of a wizard step. + */ + private $_navigationTemplate=null; + /** + * @var ITemplate the template for displaying the content within the wizard step. + */ + private $_contentTemplate=null; + /** + * @var TWizardNavigationContainer + */ + private $_navigationContainer=null; + + /** + * Creates child controls. + * This method mainly instantiates the content template, if any. + */ + public function createChildControls() + { + $this->getControls()->clear(); + if($this->_contentTemplate) + $this->_contentTemplate->instantiateIn($this); + } + + /** + * Ensures child controls are created. + * @param mixed event parameter + */ + public function onInit($param) + { + parent::onInit($param); + $this->ensureChildControls(); + } + + /** + * @return ITemplate the template for the content of the wizard step. + */ + public function getContentTemplate() + { + return $this->_contentTemplate; + } + + /** + * @param ITemplate the template for the content of the wizard step. + */ + public function setContentTemplate($value) + { + $this->_contentTemplate=$value; + } + + /** + * @return ITemplate the template for displaying the navigation UI of a wizard step. Defaults to null. + */ + public function getNavigationTemplate() + { + return $this->_navigationTemplate; + } + + /** + * @param ITemplate the template for displaying the navigation UI of a wizard step. + */ + public function setNavigationTemplate($value) + { + $this->_navigationTemplate=$value; + } + + /** + * @return TWizardNavigationContainer the control containing the navigation. + * It could be null if no navigation template is specified. + */ + public function getNavigationContainer() + { + return $this->_navigationContainer; + } + + /** + * Instantiates the navigation template if any + */ + public function instantiateNavigationTemplate() + { + if(!$this->_navigationContainer && $this->_navigationTemplate) + { + $this->_navigationContainer=new TWizardNavigationContainer; + $this->_navigationTemplate->instantiateIn($this->_navigationContainer); + } + } +} + + +/** + * TWizardStepCollection class. + * + * TWizardStepCollection represents the collection of wizard steps owned + * by a {@link TWizard}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardStepCollection extends TList +{ + /** + * @var TWizard + */ + private $_wizard; + + /** + * Constructor. + * @param TWizard wizard that owns this collection + */ + public function __construct(TWizard $wizard) + { + $this->_wizard=$wizard; + } + + /** + * Inserts an item at the specified position. + * This method overrides the parent implementation by checking if + * the item being added is a {@link TWizardStep}. + * @param integer the speicified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item being added is not TWizardStep. + */ + public function insertAt($index,$item) + { + if($item instanceof TWizardStep) + { + parent::insertAt($index,$item); + $this->_wizard->getMultiView()->getViews()->insertAt($index,$item); + $this->_wizard->addedWizardStep($item); + } + else + throw new TInvalidDataTypeException('wizardstepcollection_wizardstep_required'); + } + + /** + * Removes an item at the specified position. + * @param integer the index of the item to be removed. + * @return mixed the removed item. + */ + public function removeAt($index) + { + $step=parent::removeAt($index); + $this->_wizard->getMultiView()->getViews()->remove($step); + $this->_wizard->removedWizardStep($step); + return $step; + } +} + + +/** + * TWizardNavigationContainer class. + * + * TWizardNavigationContainer represents a control containing + * a wizard navigation. The navigation may contain a few buttons, including + * {@link getPreviousButton PreviousButton}, {@link getNextButton NextButton}, + * {@link getCancelButton CancelButton}, {@link getCompleteButton CompleteButton}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardNavigationContainer extends TControl implements INamingContainer +{ + private $_previousButton=null; + private $_nextButton=null; + private $_cancelButton=null; + private $_completeButton=null; + + /** + * @return mixed the previous button + */ + public function getPreviousButton() + { + return $this->_previousButton; + } + + /** + * @param mixed the previous button + */ + public function setPreviousButton($value) + { + $this->_previousButton=$value; + } + + /** + * @return mixed the next button + */ + public function getNextButton() + { + return $this->_nextButton; + } + + /** + * @param mixed the next button + */ + public function setNextButton($value) + { + $this->_nextButton=$value; + } + + /** + * @return mixed the cancel button + */ + public function getCancelButton() + { + return $this->_cancelButton; + } + + /** + * @param mixed the cancel button + */ + public function setCancelButton($value) + { + $this->_cancelButton=$value; + } + + /** + * @return mixed the complete button + */ + public function getCompleteButton() + { + return $this->_completeButton; + } + + /** + * @param mixed the complete button + */ + public function setCompleteButton($value) + { + $this->_completeButton=$value; + } +} + + +/** + * TWizardNavigationEventParameter class. + * + * TWizardNavigationEventParameter represents the parameter for + * {@link TWizard}'s navigation events. + * + * The index of the currently active step can be obtained from + * {@link getCurrentStepIndex CurrentStepIndex}, while the index + * of the candidate new step is in {@link getNextStepIndex NextStepIndex}. + * By modifying {@link setNextStepIndex NextStepIndex}, the new step + * can be changed to another one. If there is anything wrong with + * the navigation and it is not wanted, set {@link setCancelNavigation CancelNavigation} + * to true. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardNavigationEventParameter extends TEventParameter +{ + private $_cancel=false; + private $_currentStep; + private $_nextStep; + + /** + * Constructor. + * @param integer current step index + */ + public function __construct($currentStep) + { + $this->_currentStep=$currentStep; + $this->_nextStep=$currentStep; + } + + /** + * @return integer the zero-based index of the currently active step. + */ + public function getCurrentStepIndex() + { + return $this->_currentStep; + } + + /** + * @return integer the zero-based index of the next step. Default to {@link getCurrentStepIndex CurrentStepIndex}. + */ + public function getNextStepIndex() + { + return $this->_nextStep; + } + + /** + * @param integer the zero-based index of the next step. + */ + public function setNextStepIndex($index) + { + $this->_nextStep=TPropertyValue::ensureInteger($index); + } + + /** + * @return boolean whether navigation to the next step should be canceled. Default to false. + */ + public function getCancelNavigation() + { + return $this->_cancel; + } + + /** + * @param boolean whether navigation to the next step should be canceled. + */ + public function setCancelNavigation($value) + { + $this->_cancel=TPropertyValue::ensureBoolean($value); + } +} + +/** + * TWizardSideBarTemplate class. + * TWizardSideBarTemplate is the default template for wizard sidebar. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardSideBarTemplate extends TComponent implements ITemplate +{ + /** + * Instantiates the template. + * It creates a {@link TDataList} control. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $dataList=new TDataList; + $dataList->setID(TWizard::ID_SIDEBAR_LIST); + $dataList->getSelectedItemStyle()->getFont()->setBold(true); + $dataList->setItemTemplate(new TWizardSideBarListItemTemplate); + $parent->getControls()->add($dataList); + } +} + +/** + * TWizardSideBarListItemTemplate class. + * TWizardSideBarListItemTemplate is the default template for each item in the sidebar datalist. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardSideBarListItemTemplate extends TComponent implements ITemplate +{ + /** + * Instantiates the template. + * It creates a {@link TLinkButton}. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $button=new TLinkButton; + $button->setID(TWizard::ID_SIDEBAR_BUTTON); + $parent->getControls()->add($button); + } +} + +/** + * TWizardNavigationTemplate class. + * TWizardNavigationTemplate is the base class for various navigation templates. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardNavigationTemplate extends TComponent implements ITemplate +{ + private $_wizard; + + /** + * Constructor. + * @param TWizard the wizard owning this template + */ + public function __construct($wizard) + { + $this->_wizard=$wizard; + } + + /** + * @return TWizard the wizard owning this template + */ + public function getWizard() + { + return $this->_wizard; + } + + /** + * Instantiates the template. + * Derived classes should override this method. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + } + + /** + * Creates a navigation button. + * It creates a {@link TButton}, {@link TLinkButton}, or {@link TImageButton}, + * depending on the given parameters. + * @param TWizardNavigationButtonStyle button style + * @param boolean whether the button should cause validation + * @param string command name for the button's OnCommand event + * @throws TInvalidDataValueException if the button type is not recognized + */ + protected function createNavigationButton($buttonStyle,$causesValidation,$commandName) + { + switch($buttonStyle->getButtonType()) + { + case TWizardNavigationButtonType::Button: + $button=new TButton; + break; + case TWizardNavigationButtonType::Link: + $button=new TLinkButton; + break; + case TWizardNavigationButtonType::Image: + $button=new TImageButton; + $button->setImageUrl($buttonStyle->getImageUrl()); + break; + default: + throw new TInvalidDataValueException('wizard_buttontype_unknown',$buttonStyle->getButtonType()); + } + $button->setText($buttonStyle->getButtonText()); + $button->setCausesValidation($causesValidation); + $button->setCommandName($commandName); + return $button; + } +} + +/** + * TWizardStartNavigationTemplate class. + * TWizardStartNavigationTemplate is the template used as default wizard start navigation panel. + * It consists of two buttons, Next and Cancel. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardStartNavigationTemplate extends TWizardNavigationTemplate +{ + /** + * Instantiates the template. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $nextButton=$this->createNavigationButton($this->getWizard()->getStartNextButtonStyle(),true,TWizard::CMD_NEXT); + $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL); + + $controls=$parent->getControls(); + $controls->add($nextButton); + $controls->add("\n"); + $controls->add($cancelButton); + + $parent->setNextButton($nextButton); + $parent->setCancelButton($cancelButton); + } +} + +/** + * TWizardFinishNavigationTemplate class. + * TWizardFinishNavigationTemplate is the template used as default wizard finish navigation panel. + * It consists of three buttons, Previous, Complete and Cancel. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardFinishNavigationTemplate extends TWizardNavigationTemplate +{ + /** + * Instantiates the template. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $previousButton=$this->createNavigationButton($this->getWizard()->getFinishPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS); + $completeButton=$this->createNavigationButton($this->getWizard()->getFinishCompleteButtonStyle(),true,TWizard::CMD_COMPLETE); + $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL); + + $controls=$parent->getControls(); + $controls->add($previousButton); + $controls->add("\n"); + $controls->add($completeButton); + $controls->add("\n"); + $controls->add($cancelButton); + + $parent->setPreviousButton($previousButton); + $parent->setCompleteButton($completeButton); + $parent->setCancelButton($cancelButton); + } +} + +/** + * TWizardStepNavigationTemplate class. + * TWizardStepNavigationTemplate is the template used as default wizard step navigation panel. + * It consists of three buttons, Previous, Next and Cancel. + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardStepNavigationTemplate extends TWizardNavigationTemplate +{ + /** + * Instantiates the template. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $previousButton=$this->createNavigationButton($this->getWizard()->getStepPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS); + $nextButton=$this->createNavigationButton($this->getWizard()->getStepNextButtonStyle(),true,TWizard::CMD_NEXT); + $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL); + + $controls=$parent->getControls(); + $controls->add($previousButton); + $controls->add("\n"); + $controls->add($nextButton); + $controls->add("\n"); + $controls->add($cancelButton); + + $parent->setPreviousButton($previousButton); + $parent->setNextButton($nextButton); + $parent->setCancelButton($cancelButton); + } +} + + +/** + * TWizardNavigationButtonType class. + * TWizardNavigationButtonType defines the enumerable type for the possible types of buttons + * that can be used in the navigation part of a {@link TWizard}. + * + * The following enumerable values are defined: + * - Button: a regular click button + * - Image: an image button + * - Link: a hyperlink button + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TWizardNavigationButtonType extends TEnumerable +{ + const Button='Button'; + const Image='Image'; + const Link='Link'; +} + + +/** + * TWizardStepType class. + * TWizardStepType defines the enumerable type for the possible types of {@link TWizard wizard} steps. + * + * The following enumerable values are defined: + * - Auto: the type is automatically determined based on the location of the wizard step in the whole step collection. + * - Complete: the step is the last summary step. + * - Start: the step is the first step + * - Step: the step is between the begin and the end steps. + * - Finish: the last step before the Complete step. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0.4 + */ +class TWizardStepType extends TEnumerable +{ + const Auto='Auto'; + const Complete='Complete'; + const Start='Start'; + const Step='Step'; + const Finish='Finish'; +} + diff --git a/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php b/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php index 0e05c556..c3b4b603 100644 --- a/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php +++ b/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php @@ -1,155 +1,155 @@ -<?php
-/**
- * TWizardNavigationButtonStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php +/** + * TWizardNavigationButtonStyle class file. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2012 PradoSoft - * @license http://www.pradosoft.com/license/
- * @version $Id $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TStyle');
-
-/**
- * TWizardNavigationButtonStyle class.
- * TWizardNavigationButtonStyle defines the style applied to a wizard navigation button.
- * The button type can be specified via {@link setButtonType ButtonType}, which
- * can be 'Button', 'Image' or 'Link'.
- * If the button is an image button, {@link setImageUrl ImageUrl} will be
- * used to load the image for the button.
- * Otherwise, {@link setButtonText ButtonText} will be displayed as the button caption.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationButtonStyle extends TStyle
-{
- private $_imageUrl=null;
- private $_buttonText=null;
- private $_buttonType=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TWizardNavigationButtonStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_imageUrl=null;
- $this->_buttonText=null;
- $this->_buttonType=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TWizardNavigationButtonStyle)
- {
- if($this->_imageUrl===null && $style->_imageUrl!==null)
- $this->_imageUrl=$style->_imageUrl;
- if($this->_buttonText===null && $style->_buttonText!==null)
- $this->_buttonText=$style->_buttonText;
- if($this->_buttonType===null && $style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TWizardNavigationButtonStyle)
- {
- if($style->_imageUrl!==null)
- $this->_imageUrl=$style->_imageUrl;
- if($style->_buttonText!==null)
- $this->_buttonText=$style->_buttonText;
- if($style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * @return string image URL for the image button
- */
- public function getImageUrl()
- {
- return $this->_imageUrl===null?'':$this->_imageUrl;
- }
-
- /**
- * @param string image URL for the image button
- */
- public function setImageUrl($value)
- {
- $this->_imageUrl=$value;
- }
-
- /**
- * @return string button caption
- */
- public function getButtonText()
- {
- return $this->_buttonText===null?'':$this->_buttonText;
- }
-
- /**
- * @param string button caption
- */
- public function setButtonText($value)
- {
- $this->_buttonText=$value;
- }
-
- /**
- * @return TWizardNavigationButtonType button type. Default to TWizardNavigationButtonType::Button.
- */
- public function getButtonType()
- {
- return $this->_buttonType===null? TWizardNavigationButtonType::Button :$this->_buttonType;
- }
-
- /**
- * @param TWizardNavigationButtonType button type.
- */
- public function setButtonType($value)
- {
- $this->_buttonType=TPropertyValue::ensureEnum($value,'TWizardNavigationButtonType');
- }
-
- /**
- * Applies this style to the specified button
- * @param mixed button to be applied with this style
- */
- public function apply($button)
- {
- if($button instanceof TImageButton)
- {
- if($button->getImageUrl()==='')
- $button->setImageUrl($this->getImageUrl());
- }
- if($button->getText()==='')
- $button->setText($this->getButtonText());
- $button->getStyle()->mergeWith($this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/ + * @version $Id $ + * @package System.Web.UI.WebControls + */ + +/** + * Includes TStyle class file + */ +Prado::using('System.Web.UI.WebControls.TStyle'); + +/** + * TWizardNavigationButtonStyle class. + * TWizardNavigationButtonStyle defines the style applied to a wizard navigation button. + * The button type can be specified via {@link setButtonType ButtonType}, which + * can be 'Button', 'Image' or 'Link'. + * If the button is an image button, {@link setImageUrl ImageUrl} will be + * used to load the image for the button. + * Otherwise, {@link setButtonText ButtonText} will be displayed as the button caption. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @version $Id$ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TWizardNavigationButtonStyle extends TStyle +{ + private $_imageUrl=null; + private $_buttonText=null; + private $_buttonType=null; + + /** + * Sets the style attributes to default values. + * This method overrides the parent implementation by + * resetting additional TWizardNavigationButtonStyle specific attributes. + */ + public function reset() + { + parent::reset(); + $this->_imageUrl=null; + $this->_buttonText=null; + $this->_buttonType=null; + } + + /** + * Copies the fields in a new style to this style. + * If a style field is set in the new style, the corresponding field + * in this style will be overwritten. + * @param TStyle the new style + */ + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TWizardNavigationButtonStyle) + { + if($this->_imageUrl===null && $style->_imageUrl!==null) + $this->_imageUrl=$style->_imageUrl; + if($this->_buttonText===null && $style->_buttonText!==null) + $this->_buttonText=$style->_buttonText; + if($this->_buttonType===null && $style->_buttonType!==null) + $this->_buttonType=$style->_buttonType; + } + } + + /** + * Merges the style with a new one. + * If a style field is not set in this style, it will be overwritten by + * the new one. + * @param TStyle the new style + */ + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TWizardNavigationButtonStyle) + { + if($style->_imageUrl!==null) + $this->_imageUrl=$style->_imageUrl; + if($style->_buttonText!==null) + $this->_buttonText=$style->_buttonText; + if($style->_buttonType!==null) + $this->_buttonType=$style->_buttonType; + } + } + + /** + * @return string image URL for the image button + */ + public function getImageUrl() + { + return $this->_imageUrl===null?'':$this->_imageUrl; + } + + /** + * @param string image URL for the image button + */ + public function setImageUrl($value) + { + $this->_imageUrl=$value; + } + + /** + * @return string button caption + */ + public function getButtonText() + { + return $this->_buttonText===null?'':$this->_buttonText; + } + + /** + * @param string button caption + */ + public function setButtonText($value) + { + $this->_buttonText=$value; + } + + /** + * @return TWizardNavigationButtonType button type. Default to TWizardNavigationButtonType::Button. + */ + public function getButtonType() + { + return $this->_buttonType===null? TWizardNavigationButtonType::Button :$this->_buttonType; + } + + /** + * @param TWizardNavigationButtonType button type. + */ + public function setButtonType($value) + { + $this->_buttonType=TPropertyValue::ensureEnum($value,'TWizardNavigationButtonType'); + } + + /** + * Applies this style to the specified button + * @param mixed button to be applied with this style + */ + public function apply($button) + { + if($button instanceof TImageButton) + { + if($button->getImageUrl()==='') + $button->setImageUrl($this->getImageUrl()); + } + if($button->getText()==='') + $button->setText($this->getButtonText()); + $button->getStyle()->mergeWith($this); + } +} + diff --git a/framework/Web/UI/WebControls/assets/captcha.php b/framework/Web/UI/WebControls/assets/captcha.php index b26df895..08a857b5 100644 --- a/framework/Web/UI/WebControls/assets/captcha.php +++ b/framework/Web/UI/WebControls/assets/captcha.php @@ -1,224 +1,224 @@ -<?php
-/**
- * CAPTCHA generator script.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls.assets
- */
-
-define('THEME_OPAQUE_BACKGROUND',0x0001);
-define('THEME_NOISY_BACKGROUND',0x0002);
-define('THEME_HAS_GRID',0x0004);
-define('THEME_HAS_SCRIBBLE',0x0008);
-define('THEME_MORPH_BACKGROUND',0x0010);
-define('THEME_SHADOWED_TEXT',0x0020);
-
-require_once(dirname(__FILE__).'/captcha_key.php');
-
-$token='error';
-$theme=0;
-
-if(isset($_GET['options']))
-{
- $str=base64_decode($_GET['options']);
- if(strlen($str)>32)
- {
- $hash=substr($str,0,32);
- $str=substr($str,32);
- if(md5($privateKey.$str)===$hash)
- {
- $options=unserialize($str);
- $publicKey=$options['publicKey'];
- $tokenLength=$options['tokenLength'];
- $caseSensitive=$options['caseSensitive'];
- $alphabet=$options['alphabet'];
- $fontSize=$options['fontSize'];
- $theme=$options['theme'];
- if(($randomSeed=$options['randomSeed'])>0)
- srand($randomSeed);
- else
- srand((int)(microtime()*1000000));
- $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive);
- }
- }
-}
-
-displayToken($token,$fontSize,$theme);
-
-function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
-{
- $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
- return $caseSensitive?$token:strtoupper($token);
-}
-
-function hash2string($hex,$alphabet)
-{
- if(strlen($alphabet)<2)
- $alphabet='234578adefhijmnrtABDEFGHJLMNRT';
- $hexLength=strlen($hex);
- $base=strlen($alphabet);
- $result='';
- for($i=0;$i<$hexLength;$i+=6)
- {
- $number=hexdec(substr($hex,$i,6));
- while($number)
- {
- $result.=$alphabet[$number%$base];
- $number=floor($number/$base);
- }
- }
- return $result;
-}
-
-function displayToken($token,$fontSize,$theme)
-{
- if(($fontSize=(int)$fontSize)<22)
- $fontSize=22;
- if($fontSize>100)
- $fontSize=100;
- $length=strlen($token);
- $padding=10;
- $fontWidth=$fontSize;
- $fontHeight=floor($fontWidth*1.5);
- $width=$fontWidth*$length+$padding*2;
- $height=$fontHeight;
- $image=imagecreatetruecolor($width,$height);
-
- addBackground
- (
- $image, $width, $height,
- $theme&THEME_OPAQUE_BACKGROUND,
- $theme&THEME_NOISY_BACKGROUND,
- $theme&THEME_HAS_GRID,
- $theme&THEME_HAS_SCRIBBLE,
- $theme&THEME_MORPH_BACKGROUND
- );
-
- $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf';
-
- if(function_exists('imagefilter'))
- imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR);
-
- $hasShadow=($theme&THEME_SHADOWED_TEXT);
- for($i=0;$i<$length;$i++)
- {
- $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
- $size=rand($fontWidth-10,$fontWidth);
- $angle=rand(-30,30);
- $x=$padding+$i*$fontWidth;
- $y=rand($fontHeight-15,$fontHeight-10);
- imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]);
- if($hasShadow)
- imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]);
- imagecolordeallocate($image,$color);
- }
-
- header('Content-Type: image/png');
- imagepng($image);
- imagedestroy($image);
-}
-
-function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph)
-{
- $background=imagecreatetruecolor($width*2,$height*2);
- $white=imagecolorallocate($background,255,255,255);
- imagefill($background,0,0,$white);
-
- if($opaque)
- imagefill($background,0,0,imagecolorallocate($background,100,100,100));
-
- if($noisy)
- addNoise($background,$width*2,$height*2);
-
- if($hasGrid)
- addGrid($background,$width*2,$height*2);
-
- if($hasScribble)
- addScribble($background,$width*2,$height*2);
-
- if($morph)
- morphImage($background,$width*2,$height*2);
-
- imagecopy($image,$background,0,0,30,30,$width,$height);
-
- if(!$opaque)
- imagecolortransparent($image,$white);
-}
-
-function addNoise($image,$width,$height)
-{
- for($x=0;$x<$width;++$x)
- {
- for($y=0;$y<$height;++$y)
- {
- if(rand(0,100)<25)
- {
- $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
- imagesetpixel($image,$x,$y,$color);
- imagecolordeallocate($image,$color);
- }
- }
- }
-}
-
-function addGrid($image,$width,$height)
-{
- for($i=0;$i<$width;$i+=rand(15,25))
- {
- imagesetthickness($image,rand(2,6));
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color);
- imagecolordeallocate($image,$color);
- }
- for($i=0;$i<$height;$i+=rand(15,25))
- {
- imagesetthickness($image,rand(2,6));
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color);
- imagecolordeallocate($image,$color);
- }
-}
-
-function addScribble($image,$width,$height)
-{
- for($i=0;$i<8;$i++)
- {
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- $points=array();
- for($j=1;$j<rand(5,10);$j++)
- {
- $points[]=rand(2*(20*($i+1)),2*(50*($i+1)));
- $points[]=rand(30,$height+30);
- }
- imagesetthickness($image,rand(2,6));
- imagepolygon($image,$points,intval(sizeof($points)/2),$color);
- imagecolordeallocate($image,$color);
- }
-}
-
-function morphImage($image,$width,$height)
-{
- $tempImage=imagecreatetruecolor($width,$height);
- $chunk=rand(1,5);
- for($x=$y=0;$x<$width;$x+=$chunk)
- {
- $chunk=rand(1,5);
- $y+=rand(-1,1);
- if($y>=$height) $y=$height-5;
- if($y<0) $y=5;
- imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height);
- }
- for($x=$y=0;$y<$height;$y+=$chunk)
- {
- $chunk=rand(1,5);
- $x+=rand(-1,1);
- if($x>=$width) $x=$width-5;
- if($x<0) $x=5;
- imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk);
- }
-}
-
+<?php +/** + * CAPTCHA generator script. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2012 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id$ + * @package System.Web.UI.WebControls.assets + */ + +define('THEME_OPAQUE_BACKGROUND',0x0001); +define('THEME_NOISY_BACKGROUND',0x0002); +define('THEME_HAS_GRID',0x0004); +define('THEME_HAS_SCRIBBLE',0x0008); +define('THEME_MORPH_BACKGROUND',0x0010); +define('THEME_SHADOWED_TEXT',0x0020); + +require_once(dirname(__FILE__).'/captcha_key.php'); + +$token='error'; +$theme=0; + +if(isset($_GET['options'])) +{ + $str=base64_decode($_GET['options']); + if(strlen($str)>32) + { + $hash=substr($str,0,32); + $str=substr($str,32); + if(md5($privateKey.$str)===$hash) + { + $options=unserialize($str); + $publicKey=$options['publicKey']; + $tokenLength=$options['tokenLength']; + $caseSensitive=$options['caseSensitive']; + $alphabet=$options['alphabet']; + $fontSize=$options['fontSize']; + $theme=$options['theme']; + if(($randomSeed=$options['randomSeed'])>0) + srand($randomSeed); + else + srand((int)(microtime()*1000000)); + $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive); + } + } +} + +displayToken($token,$fontSize,$theme); + +function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive) +{ + $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength); + return $caseSensitive?$token:strtoupper($token); +} + +function hash2string($hex,$alphabet) +{ + if(strlen($alphabet)<2) + $alphabet='234578adefhijmnrtABDEFGHJLMNRT'; + $hexLength=strlen($hex); + $base=strlen($alphabet); + $result=''; + for($i=0;$i<$hexLength;$i+=6) + { + $number=hexdec(substr($hex,$i,6)); + while($number) + { + $result.=$alphabet[$number%$base]; + $number=floor($number/$base); + } + } + return $result; +} + +function displayToken($token,$fontSize,$theme) +{ + if(($fontSize=(int)$fontSize)<22) + $fontSize=22; + if($fontSize>100) + $fontSize=100; + $length=strlen($token); + $padding=10; + $fontWidth=$fontSize; + $fontHeight=floor($fontWidth*1.5); + $width=$fontWidth*$length+$padding*2; + $height=$fontHeight; + $image=imagecreatetruecolor($width,$height); + + addBackground + ( + $image, $width, $height, + $theme&THEME_OPAQUE_BACKGROUND, + $theme&THEME_NOISY_BACKGROUND, + $theme&THEME_HAS_GRID, + $theme&THEME_HAS_SCRIBBLE, + $theme&THEME_MORPH_BACKGROUND + ); + + $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf'; + + if(function_exists('imagefilter')) + imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR); + + $hasShadow=($theme&THEME_SHADOWED_TEXT); + for($i=0;$i<$length;$i++) + { + $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); + $size=rand($fontWidth-10,$fontWidth); + $angle=rand(-30,30); + $x=$padding+$i*$fontWidth; + $y=rand($fontHeight-15,$fontHeight-10); + imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]); + if($hasShadow) + imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]); + imagecolordeallocate($image,$color); + } + + header('Content-Type: image/png'); + imagepng($image); + imagedestroy($image); +} + +function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph) +{ + $background=imagecreatetruecolor($width*2,$height*2); + $white=imagecolorallocate($background,255,255,255); + imagefill($background,0,0,$white); + + if($opaque) + imagefill($background,0,0,imagecolorallocate($background,100,100,100)); + + if($noisy) + addNoise($background,$width*2,$height*2); + + if($hasGrid) + addGrid($background,$width*2,$height*2); + + if($hasScribble) + addScribble($background,$width*2,$height*2); + + if($morph) + morphImage($background,$width*2,$height*2); + + imagecopy($image,$background,0,0,30,30,$width,$height); + + if(!$opaque) + imagecolortransparent($image,$white); +} + +function addNoise($image,$width,$height) +{ + for($x=0;$x<$width;++$x) + { + for($y=0;$y<$height;++$y) + { + if(rand(0,100)<25) + { + $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220)); + imagesetpixel($image,$x,$y,$color); + imagecolordeallocate($image,$color); + } + } + } +} + +function addGrid($image,$width,$height) +{ + for($i=0;$i<$width;$i+=rand(15,25)) + { + imagesetthickness($image,rand(2,6)); + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color); + imagecolordeallocate($image,$color); + } + for($i=0;$i<$height;$i+=rand(15,25)) + { + imagesetthickness($image,rand(2,6)); + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color); + imagecolordeallocate($image,$color); + } +} + +function addScribble($image,$width,$height) +{ + for($i=0;$i<8;$i++) + { + $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180)); + $points=array(); + for($j=1;$j<rand(5,10);$j++) + { + $points[]=rand(2*(20*($i+1)),2*(50*($i+1))); + $points[]=rand(30,$height+30); + } + imagesetthickness($image,rand(2,6)); + imagepolygon($image,$points,intval(sizeof($points)/2),$color); + imagecolordeallocate($image,$color); + } +} + +function morphImage($image,$width,$height) +{ + $tempImage=imagecreatetruecolor($width,$height); + $chunk=rand(1,5); + for($x=$y=0;$x<$width;$x+=$chunk) + { + $chunk=rand(1,5); + $y+=rand(-1,1); + if($y>=$height) $y=$height-5; + if($y<0) $y=5; + imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height); + } + for($x=$y=0;$y<$height;$y+=$chunk) + { + $chunk=rand(1,5); + $x+=rand(-1,1); + if($x>=$width) $x=$width-5; + if($x<0) $x=5; + imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk); + } +} + |