diff options
Diffstat (limited to 'lib/prado/framework/Web/UI/ActiveControls')
45 files changed, 9946 insertions, 0 deletions
diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php new file mode 100644 index 0000000..ae5b7f0 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveButton.php @@ -0,0 +1,130 @@ +<?php +/** + * TActiveButton class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php new file mode 100644 index 0000000..034666f --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBox.php @@ -0,0 +1,179 @@ +<?php +/** + * TActiveCheckBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveCheckBox class. + * + * The active control counter part to checkbox. The {@link setAutoPostBack AutoPostBack} + * property is set to true by default. Thus, when the checkbox is clicked a + * {@link onCallback OnCallback} event is raise after {@link OnCheckedChanged} event. + * + * The {@link setText Text} and {@link setChecked Checked} properties can be + * changed during a callback. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveCheckBox extends TCheckBox 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)); + $this->setAutoPostBack(true); + } + + /** + * @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); + } + + /** + * 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()->update( + $this->getDefaultLabelID(), $value); + } + + /** + * Sets a value indicating whether the checkbox is to be checked or not. + * Updates checkbox checked state on the client-side if the + * {@link setEnableUpdate EnableUpdate} property is set to true. + * @param boolean whether the checkbox is to be checked or not. + */ + public function setChecked($value) + { + $value = TPropertyValue::ensureBoolean($value); + parent::setChecked($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->check($this, $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. + * + * Since 3.1.4, the javascript code is not rendered if {@link setAutoPostBack AutoPostBack} is false + * + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string onclick js + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + parent::renderInputTag($writer,$clientID,$onclick); + if ($this->getAutoPostBack()) + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * @return string corresponding javascript class name for this TActiveCheckBox. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveCheckBox'; + } + + /** + * Overrides parent implementation to ensure label has ID. + * @return TMap list of attributes to be rendered for label beside the checkbox + */ + public function getLabelAttributes() + { + $attributes = parent::getLabelAttributes(); + $attributes['id'] = $this->getDefaultLabelID(); + return $attributes; + } + + /** + * 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('id', $this->getDefaultLabelID()); + parent::renderLabel($writer, $clientID, $text); + } + + /** + * @return string checkbox label ID; + */ + protected function getDefaultLabelID() + { + if($attributes=$this->getViewState('LabelAttributes',null)) + return TCheckBox::getLabelAttributes()->itemAt('id'); + else + return $this->getClientID().'_label'; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php new file mode 100644 index 0000000..dfcb72c --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCheckBoxList.php @@ -0,0 +1,148 @@ +<?php +/** + * TActiveCheckBoxList class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter'); + +/** + * TActiveCheckBoxList class. + * + * The active control counter part to checkbox list control. + * The {@link setAutoPostBack AutoPostBack} property is set to true by default. + * Thus, when a checkbox is clicked a {@link onCallback OnCallback} event is + * raised after {@link OnSelectedIndexChanged} event. + * + * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate} + * set to true (default is true), changes to the selection will be updated + * on the client side. + * + * List items can not be changed dynamically during a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveCheckBoxList extends TCheckBoxList 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(); + } + + /** + * Override parent implementation, no javascript is rendered here instead + * the javascript required for active control is registered in {@link addAttributesToRender}. + */ + protected function renderClientControlScript($writer) + { + } + + /** + * Creates a control used for repetition (used as a template). + * @return TControl the control to be repeated + */ + protected function createRepeatedControl() + { + $control = new TActiveCheckBoxListItem; + $control->getAdapter()->setBaseActiveControl($this->getActiveControl()); + return $control; + } + + /** + * 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); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if($this->getEnableClientScript() + && $this->getAutoPostBack() + && $this->getPage()->getClientSupportsJavaScript()) + { + $this->getActiveControl()->registerCallbackClientScript( + $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.TActiveCheckBoxList'; + } +} + +class TActiveCheckBoxListItem extends TActiveCheckBox +{ + /** + * Override client implementation to avoid emitting the javascript + * + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string onclick js + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + TCheckBox::renderInputTag($writer,$clientID,$onclick); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php new file mode 100755 index 0000000..4093d8f --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveClientScript.php @@ -0,0 +1,80 @@ +<?php +/** + * TActiveClientScript class file + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php new file mode 100644 index 0000000..0cd39c7 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -0,0 +1,561 @@ +<?php +/** + * TActiveControlAdapter and TCallbackPageStateTracker class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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; + /** + * @var string view state tracker class. + */ + private $_stateTrackerClass='TCallbackPageStateTracker'; + + /** + * 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'); + if($this->_control->getVisible(false)) + { + parent::render($writer); + } else { + $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>"); + } + } + + /** + * @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()) + { + $stateTrackerClass = $this->_stateTrackerClass; + $this->_stateTracker = new $stateTrackerClass($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; + } + + /** + * @param string state tracker class. + */ + public function setStateTracker($value) + { + $this->_stateTrackerClass = TPropertyValue::ensureString($value); + } +} + +/** + * TCallbackPageStateTracker class. + * + * Tracking changes to the page state during callback. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @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 + */ + protected $_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> + * @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> + * @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> + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php new file mode 100644 index 0000000..18f9f5f --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveCustomValidator.php @@ -0,0 +1,262 @@ +<?php +/** + * TActiveCustomValidator class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php new file mode 100644 index 0000000..60a9ae3 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataGrid.php @@ -0,0 +1,851 @@ +<?php +/** + * TActiveDataGrid class file + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @link http://www.landwehr-software.de/ + * @copyright Copyright © 2009 LANDWEHR Computer und Software GmbH + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Includes the following used classes + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +Prado::using('System.Web.UI.ActiveControls.TActiveLinkButton'); +Prado::using('System.Web.UI.ActiveControls.TActiveImageButton'); +Prado::using('System.Web.UI.ActiveControls.TActiveButton'); +Prado::using('System.Web.UI.ActiveControls.TActiveImage'); +Prado::using('System.Web.UI.ActiveControls.TActiveCheckBox'); +Prado::using('System.Web.UI.ActiveControls.TCallbackOptions'); +Prado::using('System.Web.UI.WebControls.TDataGrid'); +Prado::using('System.Web.UI.WebControls.TBoundColumn'); +Prado::using('System.Web.UI.WebControls.TEditCommandColumn'); +Prado::using('System.Web.UI.WebControls.TButtonColumn'); +Prado::using('System.Web.UI.WebControls.THyperLinkColumn'); +Prado::using('System.Web.UI.WebControls.TCheckBoxColumn'); + +/** + * TActiveDataGrid class + * + * TActiveDataGrid represents a data bound and updatable grid control which is the + * active counterpart to the original {@link TDataGrid} control. + * + * This component can be used in the same way as the regular datagrid, the only + * difference is that the active datagrid uses callbacks instead of postbacks + * for interaction. + * + * There are also active datagrid columns to work with the TActiveDataGrid, which are + * - {@link TActiveBoundColumn}, the active counterpart to {@link TBoundColumn}. + * - {@link TActiveLiteralColumn}, the active counterpart to {@link TLiteralColumn}. + * - {@link TActiveCheckBoxColumn}, the active counterpart to {@link TCheckBoxColumn}. + * - {@link TActiveDropDownListColumn}, the active counterpart to {@link TDropDownListColumn}. + * - {@link TActiveHyperLinkColumn}, the active counterpart to {@link THyperLinkColumn}. + * - {@link TActiveEditCommandColumn}, the active counterpart to {@link TEditCommandColumn}. + * - {@link TActiveButtonColumn}, the active counterpart to {@link TButtonColumn}. + * - {@link TActiveTemplateColumn}, the active counterpart to {@link TTemplateColumn}. + * + * Please refer to the original documentation of the regular counterparts for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveDataGrid extends TDataGrid implements IActiveControl, ISurroundable { + + /** + * @var string the tag used to render the surrounding container + */ + protected $_surroundingTag='div'; + + /** + * @return string Name of the class used in AutoGenerateColumns mode + */ + protected function getAutoGenerateColumnName() + { + return 'TActiveBoundColumn'; + } + + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. + */ + public function __construct() { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveControl standard active control options. + */ + public function getActiveControl() { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Sets the data source object associated with the datagrid control. + * In addition, the render method of all connected pagers is called so they + * get updated when the data source is changed. Also the datagrid registers + * itself for rendering in order to get it's content replaced on client side. + * @param Traversable|array|string data source object + */ + public function setDataSource($value) { + parent::setDataSource($value); + if($this->getActiveControl()->canUpdateClientSide()) { + $this->renderPager(); + $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter()); + } + } + + /** + * Gets the tag used to render the surrounding container. Defaults to 'div'. + * @return string container tag + */ + public function getSurroundingTag() { + return $this->_surroundingTag; + } + + /** + * Sets the tag used to render the surrounding container. + * @param string $value container tag + */ + public function setSurroundingTag($value) { + $this->_surroundingTag=TPropertyValue::ensureString($value); + } + + /** + * Returns the id of the surrounding container. + * @return string container id + */ + public function getSurroundingTagID() { + return $this->getClientID().'_Container'; + } + + /** + * Creates a pager button. + * Depending on the button type, a TActiveLinkButton or a TActiveButton may be created. + * If it is enabled (clickable), its command name and parameter will also be set. + * It overrides the datagrid's original method to create active controls instead, thus + * the pager will do callbacks instead of the regular postbacks. + * @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 TActiveLinkButton; + else { + $button=new TLabel; + $button->setText($text); + return $button; + } + } + else { + $button=new TActiveButton; + if(!$enabled) + $button->setEnabled(false); + } + $button->setText($text); + $button->setCommandName($commandName); + $button->setCommandParameter($commandParameter); + $button->setCausesValidation(false); + $button->getAdapter()->getBaseActiveControl()->setClientSide( + $pager->getClientSide() + ); + return $button; + } + + protected function createPager() + { + $pager=new TActiveDataGridPager($this); + $this->buildPager($pager); + $this->onPagerCreated(new TActiveDataGridPagerEventParameter($pager)); + $this->getControls()->add($pager); + return $pager; + } + + /** + * Renders the datagrid. + * If the datagrid did not pass the prerender phase yet, it will register itself for rendering later. + * Else it will call the {@link renderDataGrid()} method which will do the rendering of the datagrid. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) { + if($this->getHasPreRendered()) { + $this->renderDataGrid($writer); + if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getSurroundingTagId(),$writer); + } + else { + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + } + } + + /** + * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate + * the datagrid for rendering. This is to ensure that the connected pagers are also rendered if the + * data source changed. + */ + private function renderPager() { + $pager=$this->getPage()->findControlsByType('TActivePager', false); + foreach($pager as $item) { + if($item->ControlToPaginate==$this->ID) { + $writer=$this->getResponse()->createHtmlWriter(); + $this->getPage()->getAdapter()->registerControlToRender($item,$writer); + } + } + } + + /** + * Renders the datagrid by writing a {@link getSurroundingTag()} with the container id obtained + * from {@link getSurroundingTagId()} which will be called by the replacement method of the client + * script to update it's content. + * @param THtmlWriter writer for the rendering purpose + */ + private function renderDataGrid($writer) { + $writer->addAttribute('id',$this->getSurroundingTagID()); + $writer->renderBeginTag($this->getSurroundingTag()); + parent::render($writer); + $writer->renderEndTag(); + } +} + + +/** + * TActiveBoundColumn class + * + * TActiveBoundColumn 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}. + * + * This is the active counterpart to the {@link TBoundColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link TBoundColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveBoundColumn extends TBoundColumn { + protected function initializeHeaderCell($cell,$columnIndex) { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) { + if($control instanceof IItemDataRenderer) { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $button->setImageUrl($url); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + if($text!=='') { + $button->setAlternateText($text); + $button->setToolTip($text); + } + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else if($text!=='') { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') { + $image->setAlternateText($text); + $image->setToolTip($text); + } + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } +} + + +/** + * TActiveEditCommandColumn class + * + * TActiveEditCommandColumn contains the Edit command buttons for editing data items in each row. + * + * TActiveEditCommandColumn 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}. + * + * This is the active counterpart to the {@link TEditCommandColumn} control. The buttons for + * interaction are replaced by active buttons. + * + * Please refer to the original documentation of the {@link TEditCommandColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveEditCommandColumn extends TEditCommandColumn { + protected function createButton($commandName,$text,$causesValidation,$validationGroup) { + if($this->getButtonType()===TButtonColumnType::LinkButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton'); + else if($this->getButtonType()===TButtonColumnType::PushButton) + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveButton'); + else // image buttons + { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $button->setToolTip($text); + 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; + } +} + + +/** + * TActiveButtonColumn class + * + * TActiveButtonColumn contains a user-defined command button, such as Add or Remove, + * that corresponds with each row in the column. + * + * This is the active counterpart to the {@link TButtonColumn} control where the + * button is replaced by the appropriate active button control. + * + * Please refer to the original documentation of the {@link TButtonColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveButtonColumn extends TButtonColumn { + 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 TActiveLinkButton; + else if($buttonType===TButtonColumnType::PushButton) + $button=new TActiveButton; + else // image button + { + $button=new TActiveImageButton; + $button->setImageUrl($this->getImageUrl()); + $button->setToolTip($this->getText()); + } + $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); + } +} + + +/** + * TActiveTemplateColumn class + * + * TActiveTemplateColumn 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. + * + * This is the active counterpart to the {@link TTemplateColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link TTemplateColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveTemplateColumn extends TTemplateColumn { + protected function initializeHeaderCell($cell,$columnIndex) { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) { + if($control instanceof IItemDataRenderer) { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $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.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } +} + +/** + * TActiveHyperLinkColumn class + * + * TActiveHyperLinkColumn contains a hyperlink for each item in the column. + * + * This is the active counterpart to the {@link THyperLinkColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link THyperLinkColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveHyperLinkColumn extends THyperLinkColumn +{ + + protected function initializeHeaderCell($cell,$columnIndex) + { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) + { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $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.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } +} + +/** + * TActiveCheckBoxColumn class + * + * TActiveCheckBoxColumn represents a checkbox column that is bound to a field in a data source. + * + * This is the active counterpart to the {@link TCheckBoxColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link TCheckBoxColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveCheckBoxColumn extends TCheckBoxColumn +{ + /** + * 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 TActiveCheckBox; + 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); + } + + protected function initializeHeaderCell($cell,$columnIndex) + { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) + { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $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.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } +} + +/** + * TActiveDropDownListColumn class + * + * TActiveDropDownListColumn represents a column that is bound to a field in a data source. + * + * This is the active counterpart to the {@link TDropDownListColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link TDropDownListColumn} for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveDropDownListColumn extends TDropDownListColumn +{ + protected function initializeHeaderCell($cell,$columnIndex) + { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') + { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) + { + if($control instanceof IItemDataRenderer) + { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) + { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') + { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $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.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') + $image->setAlternateText($text); + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } + +} + +/** + * TActiveLiteralColumn class + * + * TActiveLiteralColumn 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. + * + * This is the active counterpart to the {@link TLiteralColumn} control. For that purpose, + * if sorting is allowed, the header links/buttons are replaced by active controls. + * + * Please refer to the original documentation of the {@link TLiteralColumn} for usage. + * + * @author Fabio Bas <ctrlaltca@gmail.com> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveLiteralColumn extends TLiteralColumn { + protected function initializeHeaderCell($cell,$columnIndex) { + $text=$this->getHeaderText(); + + if(($classPath=$this->getHeaderRenderer())!=='') { + $control=Prado::createComponent($classPath); + if($control instanceof IDataRenderer) { + if($control instanceof IItemDataRenderer) { + $item=$cell->getParent(); + $control->setItemIndex($item->getItemIndex()); + $control->setItemType($item->getItemType()); + } + $control->setData($text); + } + $cell->getControls()->add($control); + } + else if($this->getAllowSorting()) { + $sortExpression=$this->getSortExpression(); + if(($url=$this->getHeaderImageUrl())!=='') { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveImageButton'); + $button->setImageUrl($url); + $button->setCommandName(TDataGrid::CMD_SORT); + $button->setCommandParameter($sortExpression); + if($text!=='') { + $button->setAlternateText($text); + $button->setToolTip($text); + } + $button->setCausesValidation(false); + $cell->getControls()->add($button); + } + else if($text!=='') { + $button=Prado::createComponent('System.Web.UI.WebControls.TActiveLinkButton'); + $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.TActiveImage'); + $image->setImageUrl($url); + if($text!=='') { + $image->setAlternateText($text); + $image->setToolTip($text); + } + $cell->getControls()->add($image); + } + else if($text!=='') + $cell->setText($text); + else + $cell->setText(' '); + } + } +} + +/** + * TActiveDataGridPager class. + * + * TActiveDataGridPager represents a pager in an activedatagrid. + * + * @author Fabio Bas <ctrlaltca@gmail.com> + * @package System.Web.UI.ActiveControls + * @since 3.2.1 + */ +class TActiveDataGridPager extends TDataGridPager +{ + protected $_callbackoptions; + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + if($this->_callbackoptions === null) + $this->_callbackoptions = new TCallbackOptions; + return $this->_callbackoptions->getClientSide(); + } +} + +/** + * TActiveDataGridPagerEventParameter class + * + * TActiveDataGridPagerEventParameter encapsulates the parameter data for + * {@link TActiveDataGrid::onPagerCreated OnPagerCreated} event of {@link TActiveDataGrid} controls. + * The {@link getPager Pager} property indicates the datagrid pager related with the event. + * + * @author Fabio Bas <ctrlaltca@gmail.com> + * @package System.Web.UI.ActiveControls + * @since 3.2.1 + */ +class TActiveDataGridPagerEventParameter extends TDataGridPagerEventParameter +{ + /** + * Constructor. + * @param TActiveDataGridPager datagrid pager related with the corresponding event + */ + public function __construct(TActiveDataGridPager $pager) + { + $this->_pager=$pager; + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php new file mode 100644 index 0000000..5bbd898 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDataList.php @@ -0,0 +1,116 @@ +<?php +/** + * TActiveDataList class file + * + * @author Marcos Aurelio Nobre <marconobre@gmail.com> + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveDataList class + * + * TActiveDataList represents a data bound and updatable grid control which is the + * active counterpart to the original {@link TDataList} control. + * + * This component can be used in the same way as the regular datalist, the only + * difference is that the active datalist uses callbacks instead of postbacks + * for interaction. + * + * Please refer to the original documentation of the regular counterparts for usage. + * + * @author Marcos Aurelio Nobre <marconobre@gmail.com> + * @package System.Web.UI.ActiveControls + */ +class TActiveDataList extends TDataList implements IActiveControl { + + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveControl standard active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Sets the data source object associated with the repeater control. + * In addition, the render method of all connected pagers is called so they + * get updated when the data source is changed. Also the repeater registers + * itself for rendering in order to get it's content replaced on client side. + * @param Traversable|array|string data source object + */ + public function setDataSource($value) + { + parent::setDataSource($value); + if($this->getActiveControl()->canUpdateClientSide()) { + $this->renderPager(); + $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter()); + } + } + + /** + * Returns the id of the surrounding container (span). + * @return string container id + */ + protected function getContainerID() + { + return $this->ClientID.'_Container'; + } + + /** + * Renders the repeater. + * If the repeater did not pass the prerender phase yet, it will register itself for rendering later. + * Else it will call the {@link renderRepeater()} method which will do the rendering of the repeater. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->getHasPreRendered()) { + $this->renderDataList($writer); + if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getContainerID(),$writer); + } + else { + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + } + } + + /** + * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate + * the repeater for rendering. This is to ensure that the connected pagers are also rendered if the + * data source changed. + */ + private function renderPager() + { + $pager=$this->getPage()->findControlsByType('TActivePager', false); + foreach($pager as $item) + { + if($item->ControlToPaginate==$this->ID) { + $writer=$this->getResponse()->createHtmlWriter(); + $this->getPage()->getAdapter()->registerControlToRender($item,$writer); + } + } + } + + /** + * Renders the repeater by writing a span tag with the container id obtained from {@link getContainerID()} + * which will be called by the replacement method of the client script to update it's content. + * @param THtmlWriter writer for the rendering purpose + */ + private function renderDataList($writer) + { + $writer->write('<span id="'.$this->getContainerID().'">'); + parent::render($writer); + $writer->write('</span>'); + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php new file mode 100755 index 0000000..6328bac --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDatePicker.php @@ -0,0 +1,198 @@ +<?php +/** + * TActiveDatePicker class file + * + * @author Bradley Booms <Bradley.Booms@nsighttel.com> + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveDatePicker class + * + * The active control counter part to date picker control. + * When the date selection is changed, the {@link onCallback OnCallback} event is + * raised. + * + * @author Bradley Booms <Bradley.Booms@nsighttel.com> + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @package System.Web.UI.ActiveControls + * @since 3.1.3 + */ +class TActiveDatePicker extends TDatePicker implements ICallbackEventHandler, IActiveControl +{ + + /** + * @return boolean a value indicating whether an automatic postback to the server + * will occur whenever the user modifies the text in the TActiveDatePicker control and + * then tabs out of the component. Defaults to true. + */ + public function getAutoPostBack() + { + return $this->getViewState('AutoPostBack',true); + } + + /** + * Sets the value indicating if postback automatically. + * An automatic postback to the server will occur whenever the user + * modifies the text in the TActiveDatePicker 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),true); + } + + /** + * Get javascript date picker options. + * @return array date picker client-side options + */ + protected function getDatePickerOptions() + { + $options = parent::getDatePickerOptions(); + $options['CausesValidation']=$this->getCausesValidation(); + $options['ValidationGroup']=$this->getValidationGroup(); + $options['EventTarget'] = $this->getUniqueID(); + $options['ShowCalendar'] = $this->getShowCalendar(); + $options['AutoPostBack'] = $this->getAutoPostBack(); + return $options; + } + + /** + * 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(); + } + + /** + * 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()){ + $cb=$this->getPage()->getCallbackClient(); + $cb->setValue($this, $value); + if ($this->getInputMode()==TDatePickerInputMode::DropDownList) + { + $s = Prado::createComponent('System.Util.TDateTimeStamp'); + $date = $s->getDate($this->getTimeStampFromText()); + $id=$this->getClientID(); + $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'day', 'Value', $date['mday'], 'select'); + $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'month', 'Value', $date['mon']-1, 'select'); + $cb->select($id.TControl::CLIENT_ID_SEPARATOR.'year', 'Value', $date['year'], 'select'); + + } + } + } + + /** + * 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); + } + + /** + * Registers the javascript code to initialize the date picker. + */ + + protected function registerCalendarClientScriptPre() + { + $cs = $this->getPage()->getClientScript(); + $cs->registerPradoScript("activedatepicker"); + } + + protected function renderClientControlScript($writer) + { + $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.TActiveDatePicker($options);"; + $cs->registerEndScript("prado:".$this->getClientID(), $code); + } + + /** + * @return TActiveDatePickerClientScript javascript validator event options. + */ + protected function createClientScript() + { + return new TActiveDatePickerClientScript; + } +} + +/** + * TActiveDatePickerClientScript class. + * + * Client-side date picker event {@link setOnDateChanged OnDateChanged} + * can be modified through the {@link TActiveDatePicker::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 Fabio Bas <ctrlaltca[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.2.1 + */ +class TActiveDatePickerClientScript extends TCallbackClientSide +{ + /** + * 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'); + } +}
\ No newline at end of file diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php new file mode 100644 index 0000000..3245ea6 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveDropDownList.php @@ -0,0 +1,143 @@ +<?php +/** + * TActiveDropDownList class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active list control adapter + */ +Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter'); + +/** + * TActiveDropDownList class. + * + * The active control counter part to drop down list control. + * The {@link setAutoPostBack AutoPostBack} property is set to true by default. + * Thus, when the drop down list selection is changed the {@link onCallback OnCallback} event is + * raised after {@link OnSelectedIndexChanged} event. + * + * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate} + * set to true (default is true), changes to the selection, <b>after</b> OnLoad event has + * been raised, will be updated. + * on the client side. + * + * List items can be changed dynamically during a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveDropDownList extends TDropDownList implements ICallbackEventHandler, IActiveControl +{ + /** + * 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() + { + parent::__construct(); + $this->setAdapter(new TActiveListControlAdapter($this)); + $this->setAutoPostBack(true); + } + + /** + * @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(); + } + + /** + * No client class for this control. + * This method overrides the parent implementation. + * @return null no javascript class name. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveDropDownList'; + } + + /** + * Creates a collection object to hold list items. A specialized + * TActiveListItemCollection is created to allow the drop down list options + * to be added. + * This method may be overriden to create a customized collection. + * @return TActiveListItemCollection the collection object + */ + protected function createListItemCollection() + { + $collection = new TActiveListItemCollection; + $collection->setControl($this); + return $collection; + } + + /** + * 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()); + if ($this->getAutoPostBack()) + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * 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); + } + + /** + * Updates the client-side options if the item list has changed after the OnLoad event. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->getAdapter()->updateListItems(); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php new file mode 100755 index 0000000..7f11115 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveFileUpload.php @@ -0,0 +1,461 @@ +<?php +/** + * TActiveFileUpload.php + * + * @author Bradley Booms <Bradley.Booms@nsighttel.com> + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @author Gabor Berczi <gabor.berczi@devworx.hu> (issue 349 remote vulnerability fix) + * @package System.Web.UI.ActiveControls + */ + +/** + * Load TActiveControlAdapter and TFileUpload. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +Prado::using('System.Web.UI.WebControls.TFileUpload'); + +/** + * TActiveFileUpload + * + * TActiveFileUpload 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. + * + * TActiveFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded + * (whether it succeeds or not). + * + * TActiveFileUpload actually does a postback in a hidden IFrame, and then does a callback. + * This callback then raises the {@link onFileUpload OnFileUpload} event. After the postback + * a status icon is displayed; either a green checkmark if the upload is successful, + * or a red x if there was an error. + * + * @author Bradley Booms <Bradley.Booms@nsighttel.com> + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @package System.Web.UI.ActiveControls + */ +class TActiveFileUpload extends TFileUpload implements IActiveControl, ICallbackEventHandler, INamingContainer +{ + + const SCRIPT_PATH = 'prado/activefileupload'; + + /** + * @var THiddenField a flag to tell which component is doing the callback. + */ + private $_flag; + /** + * @var TImage that spins to show that the file is being uploaded. + */ + private $_busy; + /** + * @var TImage that shows a green check mark for completed upload. + */ + private $_success; + /** + * @var TImage that shows a red X for incomplete upload. + */ + private $_error; + /** + * @var TInlineFrame used to submit the data in an "asynchronous" fashion. + */ + private $_target; + + + /** + * 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)); + } + + + /** + * @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; + } + + + /** + * This method is invoked when a file is uploaded. + * 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 onFileUpload($param) + { + if ($this->_flag->getValue() && $this->getPage()->getIsPostBack() && $param == $this->_target->getUniqueID()){ + // save the file so that it will persist past the end of this return. + $localName = str_replace('\\', '/', tempnam(Prado::getPathOfNamespace($this->getTempPath()),'')); + parent::saveAs($localName); + + $params = new TActiveFileUploadCallbackParams; + $params->localName = $localName; + $params->fileName = addslashes($this->getFileName()); + $params->fileSize = $this->getFileSize(); + $params->fileType = $this->getFileType(); + $params->errorCode = $this->getErrorCode(); + + // return some javascript to display a completion status. + echo <<<EOS +<script language="Javascript"> + Options = new Object(); + Options.clientID = '{$this->getClientID()}'; + Options.targetID = '{$this->_target->getUniqueID()}'; + Options.fileName = '{$params->fileName}'; + Options.fileSize = '{$params->fileSize}'; + Options.fileType = '{$params->fileType}'; + Options.errorCode = '{$params->errorCode}'; + Options.callbackToken = '{$this->pushParamsAndGetToken($params)}'; + parent.Prado.WebUI.TActiveFileUpload.onFileUpload(Options); +</script> +EOS; + + exit(); + } + } + + /** + * @return string the path where the uploaded file will be stored temporarily, in namespace format + * default "Application.runtime.*" + */ + public function getTempPath(){ + return $this->getViewState('TempPath', 'Application.runtime.*'); + } + + /** + * @param string the path where the uploaded file will be stored temporarily in namespace format + * default "Application.runtime.*" + */ + public function setTempPath($value){ + $this->setViewState('TempPath',$value,'Application.runtime.*'); + } + + /** + * @return boolean a value indicating whether an automatic callback to the server will occur whenever the user modifies the text in the TTextBox control and then tabs out of the component. Defaults to true. + * Note: When set to false, you will need to trigger the callback yourself. + */ + public function getAutoPostBack(){ + return $this->getViewState('AutoPostBack', true); + } + + /** + * @param boolean a value indicating whether an automatic callback to the server will occur whenever the user modifies the text in the TTextBox control and then tabs out of the component. Defaults to true. + * Note: When set to false, you will need to trigger the callback yourself. + */ + public function setAutoPostBack($value){ + $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),true); + } + + /** + * @return string A chuck of javascript that will need to be called if {{@link getAutoPostBack AutoPostBack} is set to false} + */ + public function getCallbackJavascript(){ + return "Prado.WebUI.TActiveFileUpload.fileChanged(\"{$this->getClientID()}\")"; + } + + /** + * @throws TInvalidDataValueException if the {@link getTempPath TempPath} is not writable. + */ + public function onInit($sender){ + parent::onInit($sender); + + if (!Prado::getApplication()->getCache()) + if (!Prado::getApplication()->getSecurityManager()) + throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely'); + + if (!is_writable(Prado::getPathOfNamespace($this->getTempPath()))){ + throw new TInvalidDataValueException("activefileupload_temppath_invalid", $this->getTempPath()); + } + } + + /** + * Raises <b>OnFileUpload</b> 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){ + $cp = $param->getCallbackParameter(); + if ($key = $cp->targetID == $this->_target->getUniqueID()){ + + $params = $this->popParamsByToken($cp->callbackToken); + + $_FILES[$key]['name'] = stripslashes($params->fileName); + $_FILES[$key]['size'] = intval($params->fileSize); + $_FILES[$key]['type'] = $params->fileType; + $_FILES[$key]['error'] = intval($params->errorCode); + $_FILES[$key]['tmp_name'] = $params->localName; + $this->loadPostData($key, null); + + $this->raiseEvent('OnFileUpload', $this, $param); + } + } + + /** + * Raises postdata changed event. + * This method calls {@link onFileUpload} method + * This method is primarily used by framework developers. + */ + public function raisePostDataChangedEvent() + { + $this->onFileUpload($this->getPage()->getRequest()->itemAt('TActiveFileUpload_TargetId')); + } + + protected function pushParamsAndGetToken(TActiveFileUploadCallbackParams $params) + { + if ($cache = Prado::getApplication()->getCache()) + { + // this is the most secure method, file info can't be forged from client side, no matter what + $token = md5('TActiveFileUpload::Params::'.$this->ClientID.'::'+rand(1000*1000,9999*1000)); + $cache->set($token, serialize($params), 5*60); // expire in 5 minutes - the callback should arrive back in seconds, actually + } + else + if ($mgr = Prado::getApplication()->getSecurityManager()) + { + // this is a less secure method, file info can be still forged from client side, but only if attacker knows the secret application key + $token = urlencode(base64_encode($mgr->encrypt(serialize($params)))); + } + else + throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely'); + + return $token; + } + + protected function popParamsByToken($token) + { + if ($cache = Prado::getApplication()->getCache()) + { + $v = $cache->get($token); + assert($v!=''); + $cache->delete($token); // remove it from cache so it can't be used again and won't take up space either + $params = unserialize($v); + } + else + if ($mgr = Prado::getApplication()->getSecurityManager()) + { + $v = $mgr->decrypt(base64_decode(urldecode($token))); + $params = unserialize($v); + } + else + throw new Exception('TActiveFileUpload needs either an application level cache or a security manager to work securely'); + + assert($params instanceof TActiveFileUploadCallbackParams); + + return $params; + } + + /** + * Publish the javascript + */ + public function onPreRender($param) + { + parent::onPreRender($param); + + if(!$this->getPage()->getIsPostBack() && isset($_GET['TActiveFileUpload_InputId']) && isset($_GET['TActiveFileUpload_TargetId']) && $_GET['TActiveFileUpload_InputId'] == $this->getClientID()) + { + // tricky workaround to intercept "uploaded file too big" error: real uploads happens in onFileUpload instead + $this->_errorCode = UPLOAD_ERR_FORM_SIZE; + $localName = str_replace('\\', '/', tempnam(Prado::getPathOfNamespace($this->getTempPath()),'')); + $fileName = addslashes($this->getFileName()); + + $params = new TActiveFileUploadCallbackParams; + $params->localName = $localName; + $params->fileName = $fileName; + $params->fileSize = $this->getFileSize(); + $params->fileType = $this->getFileType(); + $params->errorCode = $this->getErrorCode(); + + echo <<<EOS +<script language="Javascript"> + Options = new Object(); + Options.clientID = '{$_GET['TActiveFileUpload_InputId']}'; + Options.targetID = '{$_GET['TActiveFileUpload_TargetId']}'; + Options.fileName = '{$params->fileName}'; + Options.fileSize = '{$params->fileSize}'; + Options.fileType = '{$params->fileType}'; + Options.errorCode = '{$params->errorCode}'; + Options.callbackToken = '{$this->pushParamsAndGetToken($params)}'; + parent.Prado.WebUI.TActiveFileUpload.onFileUpload(Options); +</script> +EOS; + } + } + + public function createChildControls(){ + $this->_flag = Prado::createComponent('THiddenField'); + $this->_flag->setID('Flag'); + $this->getControls()->add($this->_flag); + + $this->_busy = Prado::createComponent('TImage'); + $this->_busy->setID('Busy'); + $this->_busy->setImageUrl($this->getAssetUrl('ActiveFileUploadIndicator.gif')); + $this->_busy->setStyle("display:none"); + $this->getControls()->add($this->_busy); + + $this->_success = Prado::createComponent('TImage'); + $this->_success->setID('Success'); + $this->_success->setImageUrl($this->getAssetUrl('ActiveFileUploadComplete.png')); + $this->_success->setStyle("display:none"); + $this->getControls()->add($this->_success); + + $this->_error = Prado::createComponent('TImage'); + $this->_error->setID('Error'); + $this->_error->setImageUrl($this->getAssetUrl('ActiveFileUploadError.png')); + $this->_error->setStyle("display:none"); + $this->getControls()->add($this->_error); + + $this->_target = Prado::createComponent('TInlineFrame'); + $this->_target->setID('Target'); + $this->_target->setFrameUrl($this->getAssetUrl('ActiveFileUploadBlank.html')); + $this->_target->setStyle("width:0px; height:0px;"); + $this->_target->setShowBorder(false); + $this->getControls()->add($this->_target); + } + + + /** + * Removes localfile on ending of the callback. + */ + public function onUnload($param){ + if ($this->getPage()->getIsCallback() && + $this->getHasFile() && + file_exists($this->getLocalName())){ + unlink($this->getLocalName()); + } + parent::onUnload($param); + } + + /** + * @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(); + } + + /** + * Adds ID attribute, and renders the javascript for active component. + * @param THtmlWriter the writer used for the rendering purpose + */ + public function addAttributesToRender($writer){ + parent::addAttributesToRender($writer); + $writer->addAttribute('id',$this->getClientID()); + + $this->getPage()->getClientScript()->registerPradoScript('activefileupload'); + $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(),$this->getClientOptions()); + } + + /** + * @return string corresponding javascript class name for this control. + */ + protected function getClientClassName(){ + return 'Prado.WebUI.TActiveFileUpload'; + } + + /** + * Gets the client side options for this control. + * @return array ( inputID => input client ID, + * flagID => flag client ID, + * targetName => target unique ID, + * formID => form client ID, + * indicatorID => upload indicator client ID, + * completeID => complete client ID, + * errorID => error client ID) + */ + protected function getClientOptions(){ + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + + $options['inputID'] = $this->getClientID(); + $options['flagID'] = $this->_flag->getClientID(); + $options['targetID'] = $this->_target->getUniqueID(); + $options['formID'] = $this->getPage()->getForm()->getClientID(); + $options['indicatorID'] = $this->_busy->getClientID(); + $options['completeID'] = $this->_success->getClientID(); + $options['errorID'] = $this->_error->getClientID(); + $options['autoPostBack'] = $this->getAutoPostBack(); + return $options; + } + + /** + * 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->getErrorCode()===UPLOAD_ERR_OK) && (file_exists($this->getLocalName()))){ + if ($deleteTempFile) + return rename($this->getLocalName(),$fileName); + else + return copy($this->getLocalName(),$fileName); + } else + return false; + } + + /** + * @return TImage the image displayed when an upload + * completes successfully. + */ + public function getSuccessImage(){ + $this->ensureChildControls(); + return $this->_success; + } + + /** + * @return TImage the image displayed when an upload + * does not complete successfully. + */ + public function getErrorImage(){ + $this->ensureChildControls(); + return $this->_error; + } + + /** + * @return TImage the image displayed when an upload + * is in progress. + */ + public function getBusyImage(){ + $this->ensureChildControls(); + return $this->_busy; + } +} + +/** + * TActiveFileUploadCallbackParams is an internal class used by {@link TActiveFileUpload}. + * + * @author Bradley Booms <Bradley.Booms@nsighttel.com> + * @author Christophe Boulain <Christophe.Boulain@gmail.com> + * @package System.Web.UI.ActiveControls + */ +class TActiveFileUploadCallbackParams +{ + public $localName; + public $fileName; + public $fileSize; + public $fileType; + public $errorCode; +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php new file mode 100644 index 0000000..f87ff07 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveHiddenField.php @@ -0,0 +1,116 @@ +<?php +/** + * TActiveHiddenField class file. + * + * @author Carl G. Mathisen <carlgmathisen@gmail.com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @version $Id$ + * @package System.Web.UI.ActiveControls + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +/** + * TActiveHiddenField class + * + * TActiveHiddenField displays a hidden input field on a Web page. + * The value of the input field can be accessed via {@link getValue Value} property. + * + * @author Carl G. Mathisen <carlgmathisen@gmail.com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveHiddenField extends THiddenField 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 Value property can only be updated after the OnLoad stage. + * @param string text content for the hidden field + */ + public function setValue($value) + { + parent::setValue($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.TActiveHiddenField'; + } + + /** + * 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/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php new file mode 100644 index 0000000..2ffee7e --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveHyperLink.php @@ -0,0 +1,100 @@ +<?php +/** + * TActiveHyperLink class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveHyperLink class. + * + * The active control counterpart of THyperLink component. When + * {@link TBaseActiveControl::setEnableUpdate ActiveControl.EnableUpdate} + * property is true the during a callback request, setting {@link setText Text} + * property will also set the text of the label on the client upon callback + * completion. Similarly, for other properties such as {@link setImageUrl ImageUrl}, + * {@link setNavigateUrl NavigateUrl} and {@link setTarget Target}. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveHyperLink extends THyperLink 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 basic active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * On callback response, the inner HTMl of the label is updated. + * @param string the text value of the label + */ + public function setText($value) + { + parent::setText($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->update($this, $value); + } + + /** + * Sets the location of image file of the THyperLink. + * @param string the image file location + */ + public function setImageUrl($value) + { + parent::setImageUrl($value); + if($this->getActiveControl()->canUpdateClientSide() && $value !== '') + { + $textWriter = new TTextWriter; + $renderer = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $textWriter); + $this->createImage($value)->renderControl($renderer); + $this->getPage()->getCallbackClient()->update($this, $textWriter->flush()); + } + } + + /** + * Sets the URL to link to when the THyperLink component is clicked. + * @param string the URL + */ + public function setNavigateUrl($value) + { + parent::setNavigateUrl($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + //replace & with & and urldecode the url (setting the href using javascript is literal) + $url = urldecode(str_replace('&', '&', $value)); + $this->getPage()->getCallbackClient()->setAttribute($this, 'href', $url); + } + } + + /** + * 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) + { + parent::setTarget($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'target', $value); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php new file mode 100644 index 0000000..13d5314 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveImage.php @@ -0,0 +1,90 @@ +<?php +/** + * TActiveImage class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveImage class. + * + * TActiveImage allows the {@link setAlternateText AlternateText}, + * {@link setImageAlign ImageAlign}, {@link setImageUrl ImageUrl}, + * and {@link setDescriptionUrl DescriptionUrl} to be updated during + * a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveImage extends TImage 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 basic active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Sets the alternative text to be displayed in the TImage when the image is unavailable. + * @param string the alternative text + */ + public function setAlternateText($value) + { + parent::setAlternateText($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'alt', $value); + } + + /** + * 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) + { + parent::setImageAlign($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'align', $value); + } + + /** + * @param string the URL of the image file + */ + public function setImageUrl($value) + { + parent::setImageUrl($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'src', $value); + } + + /** + * @param string the URL to the long description of the image. + */ + public function setDescriptionUrl($value) + { + parent::setDescriptionUrl($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'longdesc', $value); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php new file mode 100644 index 0000000..351a996 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveImageButton.php @@ -0,0 +1,154 @@ +<?php +/** + * TActiveImageButton class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveImageButton class. + * + * TActiveImageButton is the active control counter part to TImageButton. + * When a TActiveImageButton 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. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveImageButton extends TImageButton implements IActiveControl, ICallbackEventHandler +{ + /** + * 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 basic active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Sets the alternative text to be displayed in the TImage when the image is unavailable. + * @param string the alternative text + */ + public function setAlternateText($value) + { + parent::setAlternateText($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'alt', $value); + } + + /** + * 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) + { + parent::setImageAlign($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'align', $value); + } + + /** + * @param string the URL of the image file + */ + public function setImageUrl($value) + { + parent::setImageUrl($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'src', $value); + } + + /** + * @param string the URL to the long description of the image. + */ + public function setDescriptionUrl($value) + { + parent::setDescriptionUrl($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->setAttribute($this, 'longdesc', $value); + } + + /** + * Raises the callback event. This method is required by + * {@link ICallbackEventHandler ICallbackEventHandler} interface. If + * {@link getCausesValidation CausesValidation} is true, it will invoke the page's + * {@link TPage::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); + } + + /** + * 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 TActiveLinkButton. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveImageButton'; + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php new file mode 100644 index 0000000..70ff20e --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveLabel.php @@ -0,0 +1,88 @@ +<?php +/** + * TActiveLabel class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveLabel class + * + * The active control counterpart of TLabel component. When + * {@link TBaseActiveControl::setEnableUpdate ActiveControl.EnableUpdate} + * property is true the during a callback request, setting {@link setText Text} + * property will also set the text of the label on the client upon callback + * completion. Similarly, setting {@link setForControl ForControl} will also set + * the client-side "for" attribute on the label. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveLabel extends TLabel 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 basic active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * On callback response, the inner HTML of the label is updated. + * @param string the text value of the label + */ + public function setText($value) + { + parent::setText($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->update($this, $value); + } + + /** + * Sets the ID of the control that the label is associated with. + * The control must be locatable via {@link TControl::findControl} using the ID. + * On callback response, the For attribute of the label is updated. + * @param string the associated control ID + */ + public function setForControl($value) + { + parent::setForControl($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + $id=$this->findControl($value)->getClientID(); + $this->getPage()->getCallbackClient()->setAttribute($this, 'for', $id); + } + } + + /** + * 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); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php new file mode 100644 index 0000000..aaf2d35 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveLinkButton.php @@ -0,0 +1,159 @@ +<?php +/** + * TActiveLinkButton class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActiveLinkButton is the active control counter part to TLinkButton. + * + * When a TActiveLinkButton 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 link text upon callback response completion. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveLinkButton extends TLinkButton implements IActiveControl, ICallbackEventHandler +{ + /** + * 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 ICallbackEventHandlerICallbackEventHandler} 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 link 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()->update($this, $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()); + + if($this->getEnabled(true)) + { + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + } + + /** + * Ensures that the anchor is rendered correctly when its Enabled property + * changes in a callback + * @param bool enabled + */ + public function setEnabled($value) + { + parent::setEnabled($value); + if($this->getActiveControl()->canUpdateClientSide()) + { + if($this->getEnabled(true)) + { + $nop = "javascript:;//".$this->getClientID(); + $this->getPage()->getCallbackClient()->setAttribute($this, 'href', $nop); + + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + + } else { + $this->getPage()->getCallbackClient()->setAttribute($this, 'href', false); + } + } + } + + /** + * @return string corresponding javascript class name for this TActiveLinkButton. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveLinkButton'; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php new file mode 100644 index 0000000..e32a8eb --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveListBox.php @@ -0,0 +1,152 @@ +<?php +/** + * TActiveListBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active list control adapter + */ +Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter'); + +/** + * TActiveListBox class. + * + * List items can be added dynamically during a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveListBox extends TListBox 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() + { + parent::__construct(); + $this->setAdapter(new TActiveListControlAdapter($this)); + $this->setAutoPostBack(true); + } + + /** + * @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(); + } + + /** + * Creates a collection object to hold list items. A specialized + * TActiveListItemCollection is created to allow the drop down list options + * to be added. + * This method may be overriden to create a customized collection. + * @return TActiveListItemCollection the collection object + */ + protected function createListItemCollection() + { + $collection = new TActiveListItemCollection; + $collection->setControl($this); + return $collection; + } + + /** + * Javascript client class for this control. + * This method overrides the parent implementation. + * @return null no javascript class name. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveListBox'; + } + + /** + * Sets the selection mode of the list control (Single, Multiple) + * on the client-side if the {@link setEnableUpdate EnableUpdate} + * property is set to true. + * @param string the selection mode + */ + public function setSelectionMode($value) + { + parent::setSelectionMode($value); + $multiple = $this->getIsMultiSelect(); + $id = $this->getUniqueID(); $multi_id = $id.'[]'; + if($this->getActiveControl()->canUpdateClientSide()) + { + $client = $this->getPage()->getCallbackClient(); + $client->setAttribute($this, 'multiple', $multiple ? 'multiple' : false); + $client->setAttribute($this, 'name', $multiple ? $multi_id : $id); + } + } + + /** + * 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); + } + + /** + * Updates the client-side options if the item list has changed after the OnLoad event. + */ + public function onPreRender($param) + { + parent::onPreRender($param); + $this->getAdapter()->updateListItems(); + } + + /** + * 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()); + if ($this->getAutoPostBack()) + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php new file mode 100644 index 0000000..927912b --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveListControlAdapter.php @@ -0,0 +1,255 @@ +<?php +/** + * TActiveListControlAdapter class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +Prado::using('System.Web.UI.WebControls.TListControl'); + +/** + * TActiveListControlAdapter class. + * + * Adapte the list controls to allows the selections on the client-side to be altered + * during callback response. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveListControlAdapter extends TActiveControlAdapter implements IListControlAdapter +{ + /** + * @return boolean true if can update client-side attributes. + */ + protected function canUpdateClientSide() + { + return $this->getControl()->getActiveControl()->canUpdateClientSide(); + } + + /** + * 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) + { + if($this->canUpdateClientSide()) + { + $this->updateListItems(); + // if a prompt is set, we mimic the postback behaviour of not counting it + // in the index. We assume the prompt is _always_ the first item (Issue #368) + $promptValue=$this->getControl()->getPromptValue(); + if($promptValue==='') + $promptValue=$this->getControl()->getPromptText(); + if($promptValue!=='') + $index++; + + if($index >= 0 && $index <= $this->getControl()->getItemCount()) + $this->getPage()->getCallbackClient()->select( + $this->getControl(), 'Index', $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) + { + if($this->canUpdateClientSide()) + { + $this->updateListItems(); + $n = $this->getControl()->getItemCount(); + + $promptValue=$this->getControl()->getPromptValue(); + if($promptValue==='') + $promptValue=$this->getControl()->getPromptText(); + + $list = array(); + foreach($indices as $index) + { + $index = intval($index); + if($promptValue!=='') + $index++; + if($index >= 0 && $index <= $n) + $list[] = $index; + } + if(count($list) > 0) + $this->getPage()->getCallbackClient()->select( + $this->getControl(), 'Indices', $list); + } + } + + /** + * Sets selection by item value on the client side. + * @param string the value of the item to be selected. + */ + public function setSelectedValue($value) + { + if($this->canUpdateClientSide()) + { + $this->updateListItems(); + $this->getPage()->getCallbackClient()->select( + $this->getControl(), 'Value', $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) + { + if($this->canUpdateClientSide()) + { + $this->updateListItems(); + $list = array(); + foreach($values as $value) + $list[] = $value; + if(count($list) > 0) + $this->getPage()->getCallbackClient()->select( + $this->getControl(), 'Values', $list); + } + } + + /** + * Clears all existing selections on the client side. + */ + public function clearSelection() + { + if($this->canUpdateClientSide()) + { + $this->updateListItems(); + if($this->getControl() instanceof TActiveDropDownList) + { + // clearing a TActiveDropDownList's selection actually doesn't select the first item; + // we mimic the postback behaviour selecting it (Issue #368) + $this->getPage()->getCallbackClient()->select($this->getControl(), 'Index', 0); + } else { + $this->getPage()->getCallbackClient()->select($this->getControl(), 'Clear'); + } + } + } + + /** + * Update the client-side list options. + */ + public function updateListItems() + { + if($this->canUpdateClientSide()) + { + $items = $this->getControl()->getItems(); + if($items instanceof TActiveListItemCollection + && $items->getListHasChanged()) + { + $items->updateClientSide(); + } + } + } +} + +/** + * TActiveListItemCollection class. + * + * Allows TActiveDropDownList and TActiveListBox to add new options + * during callback response. New options can only be added <b>after</b> the + * {@link TControl::onLoad OnLoad} event. + * + * The {@link getListHasChanged ListHasChanged} property is true when the + * list items has changed. The control responsible for the list needs to + * repopulate the client-side options. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveListItemCollection extends TListItemCollection +{ + /** + * @var IActiveControl control instance. + */ + private $_control; + /** + * @var boolean true if list items were changed. + */ + private $_hasChanged=false; + + /** + * @return boolean true if active controls can update client-side and + * the onLoad event has already been raised. + */ + protected function canUpdateClientSide() + { + return $this->getControl()->getActiveControl()->canUpdateClientSide() + && $this->getControl()->getHasLoaded(); + } + + /** + * @param IActiveControl a active list control. + */ + public function setControl(IActiveControl $control) + { + $this->_control = $control; + } + + /** + * @return IActiveControl active control using the collection. + */ + public function getControl() + { + return $this->_control; + } + + /** + * @return boolean true if the list has changed after onLoad event. + */ + public function getListHasChanged() + { + return $this->_hasChanged; + } + + /** + * Update client-side list items. + */ + public function updateClientSide() + { + $client = $this->getControl()->getPage()->getCallbackClient(); + $client->setListItems($this->getControl(), $this); + $this->_hasChanged=false; + } + + /** + * Inserts an item into the collection. + * The new option is added on the client-side during callback. + * @param integer the location where the item will be inserted. + * The current item at the place and the following ones will be moved backward. + * @param TListItem the item to be inserted. + * @throws TInvalidDataTypeException if the item being inserted is neither a string nor TListItem + */ + public function insertAt($index, $value) + { + parent::insertAt($index, $value); + if($this->canUpdateClientSide()) + $this->_hasChanged = true; + } + + /** + * Removes an item from at specified index. + * @param int zero based index. + */ + public function removeAt($index) + { + parent::removeAt($index); + if($this->canUpdateClientSide()) + $this->_hasChanged = true; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php new file mode 100644 index 0000000..215706e --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveMultiView.php @@ -0,0 +1,112 @@ +<?php +/** + * TActiveMultiView class file + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @link http://www.landwehr-software.de/ + * @copyright Copyright © 2009 LANDWEHR Computer und Software GmbH + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Includes the following used classes + */ +Prado::using('System.Web.UI.WebControls.TMultiView'); + +/** + * TActiveMultiView class. + * + * TActiveMultiView is the active counterpart to the original {@link TMultiView} control. + * It re-renders on Callback when {@link setActiveView ActiveView} or + * {@link setActiveViewIndex ActiveViewIndex} is called. + * + * Please refer to the original documentation of the regular counterpart for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.6 + */ +class TActiveMultiView extends TMultiView implements IActiveControl +{ + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. + */ + public function __construct() + { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveControl standard active control options. + */ + public function getActiveControl() + { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Returns the id of the surrounding container (span). + * @return string container id + */ + protected function getContainerID() + { + return $this->ClientID.'_Container'; + } + + /** + * Renders the TActiveMultiView. + * If the MutliView did not pass the prerender phase yet, it will register itself for rendering later. + * Else it will call the {@link renderMultiView()} method which will do the rendering of the MultiView. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) + { + if($this->getHasPreRendered()) { + $this->renderMultiView($writer); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->replaceContent($this->getContainerID(),$writer); + } + else + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + } + + /** + * Renders the TActiveMultiView by writing a span tag with the container id obtained from {@link getContainerID()} + * which will be called by the replacement method of the client script to update it's content. + * @param $writer THtmlWriter writer for the rendering purpose + */ + protected function renderMultiView($writer) + { + $writer->addAttribute('id', $this->getContainerID()); + $writer->renderBeginTag('span'); + parent::render($writer); + $writer->renderEndTag(); + } + + /** + * @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) + { + $old=parent::getActiveViewIndex(); + parent::setActiveViewIndex($value); + if($this->getActiveControl()->canUpdateClientSide() && $old!=$value) + $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter()); + } + + /** + * @param TView the view to be activated + * @throws TInvalidOperationException if the view is not in the view collection + */ + public function setActiveView($value) + { + $old=parent::getActiveView(); + parent::setActiveView($value); + if($this->getActiveControl()->canUpdateClientSide() && $old!=$value) + $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter()); + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php new file mode 100644 index 0000000..1803f44 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -0,0 +1,415 @@ +<?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 https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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) + * @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'; + /** + * Stylesheet header name. + */ + const CALLBACK_STYLESHEET_HEADER = 'X-PRADO-STYLESHEET'; + /** + * 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); + } + + /** + * 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); + } + } + + //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); + } + } + + //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()->renderEndScriptsCallback($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); + + + $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 stylesheet snippets references + $stylesheets = $cs->getStyleSheetCodes(); + if (count($stylesheets)>0) + $this->appendContentPart($response, self::CALLBACK_STYLESHEET_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. + * @return string postback event parameter + */ + public function getCallbackEventParameter() + { + if($this->_callbackEventParameter===null) + { + $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER); + $this->_callbackEventParameter=$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> + * @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 = $this->getExceptionStackTrace($exception); + // avoid error on non-utf8 strings + try { + $trace = TJavaScript::jsonEncode($trace); + } catch (Exception $e) { + // strip everythin not 7bit ascii + $trace = preg_replace('/[^(\x20-\x7F)]*/','', serialize($trace)); + } + + // avoid exception loop if headers have already been sent + try { + $response->setStatusCode(500, 'Internal Server Error'); + } catch (Exception $e) { } + + $content = $response->createHtmlWriter(); + $content->getWriter()->setBoundary(TActivePageAdapter::CALLBACK_ERROR_HEADER); + $content->write($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> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TInvalidCallbackException extends TException +{ +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php new file mode 100644 index 0000000..e99743f --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePager.php @@ -0,0 +1,207 @@ +<?php +/** + * TActivePager class file. + * + * @author "gevik" (forum contributor) and Christophe Boulain (Christophe.Boulain@gmail.com) + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); + +/** + * TActivePager is the active control counter part of TPager. + * + * When a page change is requested, TActivePager raises a callback instead of the + * traditional postback. + * + * The {@link onCallback OnCallback} event is raised during a callback request + * and it is raise <b>after</b> the {@link onPageIndexChanged OnPageIndexChanged} event. + * + * @author "gevik" (forum contributor) and Christophe Boulain (Christophe.Boulain@gmail.com) + * @package System.Web.UI.ActiveControls + * @since 3.1.2 + */ +class TActivePager extends TPager implements IActiveControl, ICallbackEventHandler +{ + /** + * 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(); + } + + /** + * @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); + } + + /** + * Builds a dropdown list pager + * Override parent implementation to build Active dropdown lists. + */ + protected function buildListPager() + { + $list=new TActiveDropDownList; + + $list->getAdapter()->getBaseActiveControl()->setClientSide( + $this->getClientSide() + ); + + $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')); + $list->attachEventHandler('OnCallback', array($this, 'handleCallback')); + } + + /** + * Creates a pager button. + * Override parent implementation to create, depending on the button type, a TActiveLinkButton, + * a TActiveButton or a TActiveImageButton may be created. + * + * @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 TActiveLinkButton; + else + { + $button=new TLabel; + $button->setText($text); + $button->setCssClass($this->getButtonCssClass()); + return $button; + } + } + else if($buttonType===TPagerButtonType::ImageButton) + { + $button = new TActiveImageButton; + $button->setImageUrl($this->getPageImageUrl($text,$commandName)); + if($enabled) + $button->Visible = true; + else + $button->Visible = false; + } + else + { + $button=new TActiveButton; + if(!$enabled) + $button->setEnabled(false); + } + + if($buttonType===TPagerButtonType::ImageButton) + { + $button->ImageUrl = $text; + } + + $button->setText($text); + $button->setCommandName($commandName); + $button->setCommandParameter($commandParameter); + $button->setCausesValidation(false); + $button->setCssClass($this->getButtonCssClass()); + + $button->attachEventHandler('OnCallback', array($this, 'handleCallback')); + $button->getAdapter()->getBaseActiveControl()->setClientSide( + $this->getClientSide() + ); + + return $button; + } + + /** + * Event handler to the OnCallback active buttons or active dropdownlist. + * This handler will raise the {@link onCallback OnCallback} event + * + * @param mixed $sender + * @param TCallbackEventParameter $param + */ + public function handleCallback ($sender,$param) + { + // Update all the buttons pagers attached to the same control. + // Dropdown pagers doesn't need to be re-rendered. + $controlToPaginate=$this->getControlToPaginate(); + foreach ($this->getNamingContainer()->findControlsByType('TActivePager', false) as $control) + { + if ($control->getMode() !== TPagerMode::DropDownList && $control->getControlToPaginate()===$controlToPaginate) + { + $control->render($param->getNewWriter()); + // FIXME : With some very fast machine, the getNewWriter() consecutive calls are in the same microsecond, resulting + // of getting the same boundaries in ajax response. Wait 1 microsecond to avoid this. + usleep(1); + } + } + // Raise callback event + $this->onCallback($param); + } + + public function render ($writer) + { + if($this->getHasPreRendered()) + { + $this->setDisplay(($this->getPageCount()==1)?TDisplayStyle::None:TDisplayStyle::Dynamic); + TWebControl::render($writer); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->replaceContent($this,$writer); + } + else + { + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + } + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php b/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php new file mode 100644 index 0000000..5192b0d --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActivePanel.php @@ -0,0 +1,98 @@ +<?php +/** + * TActivePanel file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php new file mode 100644 index 0000000..90190a1 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButton.php @@ -0,0 +1,174 @@ +<?php +/** + * TActiveRadioButton class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TActiveRadioButton class. + * + * The active control counter part to radio button. The {@link setAutoPostBack AutoPostBack} + * property is set to true by default. Thus, when the radio button is clicked a + * {@link onCallback OnCallback} event is raise after {@link OnCheckedChanged} event. + * + * The {@link setText Text} and {@link setChecked Checked} properties can be + * changed during a callback. + * + * The {@link setGroupName GroupName} property may <b>NOT</b> be changed + * during callback because the client-side <tt>name</tt> attribute is read-only + * and can not be changed using javascript. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveRadioButton extends TRadioButton implements IActiveControl, ICallbackEventHandler +{ + /** + * 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->setAutoPostBack(true); + } + + /** + * @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); + } + + /** + * 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()->update( + $this->getDefaultLabelID(), $value); + } + + /** + * Checks the radio button. + * Updates radio button checked state on the client-side if the + * {@link setEnableUpdate EnableUpdate} property is set to true. + * @param boolean whether the radio button is to be checked or not. + */ + public function setChecked($value) + { + $value = TPropertyValue::ensureBoolean($value); + parent::setChecked($value); + if($this->getActiveControl()->canUpdateClientSide()) + $this->getPage()->getCallbackClient()->check($this, $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. + * Since 3.1.4, the javascript code is not rendered if {@link setAutoPostBack AutoPostBack} is false + * + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + parent::renderInputTag($writer,$clientID,$onclick); + if ($this->getAutoPostBack()) + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * @return string corresponding javascript class name for this TActiveRadioButton. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveRadioButton'; + } + + /** + * Overrides parent implementation to ensure label has ID. + * @return TMap list of attributes to be rendered for label beside the radio button + */ + public function getLabelAttributes() + { + $attributes = parent::getLabelAttributes(); + $attributes['id'] = $this->getDefaultLabelID(); + return $attributes; + } + + /** + * Renders a label beside the radio button. + * @param THtmlWriter the writer for the rendering purpose + * @param string radio button id + * @param string label text + */ + protected function renderLabel($writer,$clientID,$text) + { + $writer->addAttribute('id', $this->getDefaultLabelID()); + parent::renderLabel($writer, $clientID, $text); + } + + /** + * @return string radio button label ID; + */ + protected function getDefaultLabelID() + { + if($attributes=$this->getViewState('LabelAttributes',null)) + return $this->getLabelAttributes()->itemAt('id'); + else + return $this->getClientID().'_label'; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php new file mode 100644 index 0000000..9acb672 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRadioButtonList.php @@ -0,0 +1,145 @@ +<?php +/** + * TActiveRadioButtonList class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter and active radio button. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveListControlAdapter'); +Prado::using('System.Web.UI.ActiveControls.TActiveRadioButton'); + +/** + * TActiveRadioButtonList class. + * + * The active control counter part to radio button list control. + * The {@link setAutoPostBack AutoPostBack} property is set to true by default. + * Thus, when a radio button is clicked a {@link onCallback OnCallback} event is + * raised after {@link OnSelectedIndexChanged} event. + * + * With {@link TBaseActiveControl::setEnableUpdate() ActiveControl.EnableUpdate} + * set to true (default is true), changes to the selection will be updated + * on the client side. + * + * List items can not be changed dynamically during a callback request. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TActiveRadioButtonList extends TRadioButtonList 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(); + } + + /** + * Override parent implementation, no javascript is rendered here instead + * the javascript required for active control is registered in {@link addAttributesToRender}. + */ + protected function renderClientControlScript($writer) + { + } + + /** + * Creates a control used for repetition (used as a template). + * @return TControl the control to be repeated + */ + protected function createRepeatedControl() + { + $control = new TActiveRadioButtonItem; + $control->getAdapter()->setBaseActiveControl($this->getActiveControl()); + return $control; + } + + /** + * 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); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $this->getActiveControl()->registerCallbackClientScript( + $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.TActiveRadioButtonList'; + } + +} + + +class TActiveRadioButtonItem extends TActiveRadioButton +{ + /** + * Override client implementation to avoid emitting the javascript + * + * @param THtmlWriter the writer for the rendering purpose + * @param string checkbox id + * @param string onclick js + */ + protected function renderInputTag($writer,$clientID,$onclick) + { + TRadioButton::renderInputTag($writer,$clientID,$onclick); + } +}
\ No newline at end of file diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php new file mode 100644 index 0000000..a154eb6 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRatingList.php @@ -0,0 +1,144 @@ +<?php +/** + * TActiveRatingList class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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 = 'Prado.Registry[\''.$this->ClientID.'\'].'.$func.'('.$value.')'; + $client->evaluateScript($code,array($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); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $this->getActiveControl()->registerCallbackClientScript( + $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.TActiveRatingList'; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php new file mode 100644 index 0000000..ad97d30 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveRepeater.php @@ -0,0 +1,133 @@ +<?php +/** + * TActiveRepeater class file + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ + +/** + * TActiveRepeater class + * + * TActiveRepeater represents a data bound and updatable grid control which is the + * active counterpart to the original {@link TRepeater} control. + * + * This component can be used in the same way as the regular datagrid, the only + * difference is that the active repeater uses callbacks instead of postbacks + * for interaction. + * + * Please refer to the original documentation of the regular counterparts for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveRepeater extends TRepeater implements IActiveControl, ISurroundable { + + /** + * @var string the tag used to render the surrounding container + */ + protected $_surroundingTag='div'; + + /** + * Creates a new callback control, sets the adapter to + * TActiveControlAdapter. + */ + public function __construct() { + parent::__construct(); + $this->setAdapter(new TActiveControlAdapter($this)); + } + + /** + * @return TBaseActiveControl standard active control options. + */ + public function getActiveControl() { + return $this->getAdapter()->getBaseActiveControl(); + } + + /** + * Sets the data source object associated with the repeater control. + * In addition, the render method of all connected pagers is called so they + * get updated when the data source is changed. Also the repeater registers + * itself for rendering in order to get it's content replaced on client side. + * @param Traversable|array|string data source object + */ + public function setDataSource($value) { + parent::setDataSource($value); + if($this->getActiveControl()->canUpdateClientSide()) { + $this->renderPager(); + $this->getPage()->getAdapter()->registerControlToRender($this,$this->getResponse()->createHtmlWriter()); + } + } + + /** + * Gets the tag used to render the surrounding container. Defaults to 'div'. + * @return string container tag + */ + public function getSurroundingTag() { + return $this->_surroundingTag; + } + + /** + * Sets the tag used to render the surrounding container. + * @param string $value container tag + */ + public function setSurroundingTag($value) { + $this->_surroundingTag=TPropertyValue::ensureString($value); + } + + /** + * Returns the id of the surrounding container. + * @return string container id + */ + public function getSurroundingTagID() { + return $this->getClientID().'_Container'; + } + + /** + * Renders the repeater. + * If the repeater did not pass the prerender phase yet, it will register itself for rendering later. + * Else it will call the {@link renderRepeater()} method which will do the rendering of the repeater. + * @param THtmlWriter writer for the rendering purpose + */ + public function render($writer) { + if($this->getHasPreRendered()) { + $this->renderRepeater($writer); + if($this->getActiveControl()->canUpdateClientSide()) $this->getPage()->getCallbackClient()->replaceContent($this->getSurroundingTagId(),$writer); + } + else { + $this->getPage()->getAdapter()->registerControlToRender($this,$writer); + } + } + + /** + * Loops through all {@link TActivePager} on the page and registers the ones which are set to paginate + * the repeater for rendering. This is to ensure that the connected pagers are also rendered if the + * data source changed. + */ + private function renderPager() { + $pager=$this->getPage()->findControlsByType('TActivePager', false); + foreach($pager as $item) { + if($item->ControlToPaginate==$this->ID) { + $writer=$this->getResponse()->createHtmlWriter(); + $this->getPage()->getAdapter()->registerControlToRender($item,$writer); + } + } + } + + /** + * Renders the repeater by writing a {@link getSurroundingTag()} with the container id obtained + * from {@link getSurroundingTagID()} which will be called by the replacement method of the client + * script to update it's content. + * @param THtmlWriter writer for the rendering purpose + */ + private function renderRepeater($writer) { + $writer->addAttribute('id',$this->getSurroundingTagID()); + $writer->renderBeginTag($this->getSurroundingTag()); + parent::render($writer); + $writer->renderEndTag(); + } + +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php new file mode 100644 index 0000000..a581aa4 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableCell.php @@ -0,0 +1,252 @@ +<?php +/** + * TActiveTableCell class file + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @link http://www.landwehr-software.de/ + * @copyright Copyright © 2009 LANDWEHR Computer und Software GmbH + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + * @version $Id$ + */ + +/** + * Includes the following used classes + */ +Prado::using('System.Web.UI.WebControls.TTableRow'); +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter'); + +/** + * TActiveTableCell class. + * + * TActiveTableCell is the active counterpart to the original {@link TTableCell} control + * and displays a table cell. The horizontal and vertical alignments of the cell + * are specified via {@link setHorizontalAlign HorizontalAlign} and + * {@link setVerticalAlign VerticalAlign} properties, respectively. + * + * TActiveTableCell allows the contents of the table cell to be changed during callback. When + * {@link onCellSelected CellSelected} property is set, selecting (clicking on) the cell will + * perform a callback request causing {@link onCellSelected OnCellSelected} event to be fired. + * + * It will also bubble the {@link onCellSelected OnCellSelected} event up to it's parent + * {@link TActiveTableRow} control which will fire up the event handlers if implemented. + * + * TActiveTableCell allows the client-side cell contents to be updated during a + * callback response by getting a new writer, invoking the render method and flushing the + * output, similar to a {@link TActivePanel} control. + * <code> + * function callback_request($sender, $param) + * { + * $this->active_cell->render($param->getNewWriter()); + * } + * </code> + * + * Please refer to the original documentation of the regular counterpart for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @version $Id$ + * @since 3.1.9 + */ +class TActiveTableCell extends TTableCell implements ICallbackEventHandler, IActiveControl +{ + + /** + * @var TTable parent row control containing the cell + */ + private $_row; + + /** + * Creates a new callback control, sets the adapter to TActiveControlAdapter. + */ + 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(); + } + + /** + * @return string corresponding javascript class name for this TActiveTableCell. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveTableCell'; + } + + /** + * Raises the callback event. This method is required by {@link ICallbackEventHandler} + * interface. It will raise {@link onCellSelected OnCellSelected} event with a + * {@link TActiveTableCellEventParameter} containing the zero-based index of the + * TActiveTableCell. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $parameter = new TActiveTableCellEventParameter($this->getResponse(), $param->getCallbackParameter(), $this->getCellIndex()); + $this->onCellSelected($parameter); + $this->raiseBubbleEvent($this, $parameter); + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnCellSelected' 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 TActiveTableCellEventParameter event parameter to be passed to the event handlers + */ + public function onCellSelected($param) + { + $this->raiseEvent('OnCellSelected', $this, $param); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control if the event handler for the + * {@link onCellSelected OnCellSelected} event is set. + * @param THtmlWriter the writer responsible for rendering + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id', $this->getClientID()); + if ($this->hasEventHandler('OnCellSelected')) + $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * Renders and replaces the cell'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 we update a TActiveTableCell on callback, we shouldn't update all childs, + // because the whole content will be replaced by the parent. + if ($this->getHasControls()) + { + foreach ($this->findControlsByType('IActiveControl', false) as $control) + $control->getActiveControl()->setEnableUpdate(false); + } + } + } + + /** + * Returns postback specifications for the table cell. + * This method is used by framework and control developers. + * @return array parameters about how the row defines its postback behavior. + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } + + /** + * Returns the zero-based index of the TActiveTableCell within the {@link TTableCellCollection} + * of the parent {@link TTableRow} control. Raises a {@link TConfigurationException} if the cell + * is no member of the cell collection. + * @return integer the zero-based index of the cell + */ + public function getCellIndex() + { + foreach ($this->getRow()->getCells() as $key => $row) + if ($row == $this) return $key; + throw new TConfigurationException('tactivetablecell_control_notincollection', get_class($this), $this->getUniqueID()); + } + + /** + * Returns the parent {@link TTableRow} control by looping through all parents until a {@link TTableRow} + * is found. Raises a {@link TConfigurationException} if no row control is found. + * @return TTableRow the parent row control + */ + public function getRow() + { + if ($this->_row === null) + { + $row = $this->getParent(); + while (!($row instanceof TTableRow) && $row !== null) + { + $row = $row->getParent(); + } + if ($row instanceof TTableRow) $this->_row = $row; + else throw new TConfigurationException('tactivetablecell_control_outoftable', get_class($this), $this->getUniqueID()); + } + return $this->_row; + } + +} + +/** + * TActiveTableCellEventParameter class. + * + * The TActiveTableCellEventParameter provides the parameter passed during the callback + * requestion 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. + * + * The {@link getSelectedCellIndex SelectedCellIndex} is a zero-based index of the + * TActiveTableCell , -1 if the cell is not part of the cell collection (this shouldn't + * happen though since an exception is thrown before). + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveTableCellEventParameter extends TCallbackEventParameter +{ + + /** + * @var integer the zero-based index of the cell. + */ + private $_selectedCellIndex = -1; + + /** + * Creates a new TActiveTableRowEventParameter. + */ + public function __construct($response, $parameter, $index=-1) + { + parent::__construct($response, $parameter); + $this->_selectedCellIndex = $index; + } + + /** + * Returns the zero-based index of the {@link TActiveTableCell} within the + * {@link TTableCellCollection} of the parent {@link TTableRow} control. + * @return integer the zero-based index of the cell. + */ + public function getSelectedCellIndex() + { + return $this->_selectedCellIndex; + } + +}
\ No newline at end of file diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php new file mode 100644 index 0000000..0f8abab --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTableRow.php @@ -0,0 +1,270 @@ +<?php +/** + * TActiveTableRow and TActiveTableRowEventParameter class file + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @link http://www.landwehr-software.de/ + * @copyright Copyright © 2009 LANDWEHR Computer und Software GmbH + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + * @version $Id$ + */ + +/** + * Includes the following used classes + */ +Prado::using('System.Web.UI.WebControls.TTableRow'); +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter'); + +/** + * TActiveTableRow class. + * + * TActiveTableRow is the active counterpart to the original {@link TTableRow} control + * and 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. + * + * TActiveTableRow allows the contents of the table row to be changed during callback. When + * {@link onRowSelected RowSelected} property is set, selecting (clicking on) the row will + * perform a callback request causing {@link onRowSelected OnRowSelected} event to be fired. + * + * It will also respond to a bubbled {@link onCellSelected OnCellSelected} event of a + * {@link TActiveTableCell} child control and fire a {@link onRowSelected OnRowSelected} event. + * + * TActiveTableRow allows the client-side row contents to be updated during a + * callback response by getting a new writer, invoking the render method and flushing the + * output, similar to a {@link TActivePanel} control. + * <code> + * function callback_request($sender, $param) + * { + * $this->active_row->render($param->getNewWriter()); + * } + * </code> + * + * Please refer to the original documentation of the regular counterpart for usage. + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @version $Id$ + * @since 3.1.9 + */ +class TActiveTableRow extends TTableRow implements ICallbackEventHandler, IActiveControl +{ + + /** + * @var TTable parent table control containing the row + */ + private $_table; + + /** + * Creates a new callback control, sets the adapter to TActiveControlAdapter. + * */ + 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(); + } + + /** + * @return string corresponding javascript class name for this TActiveTableRow. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TActiveTableRow'; + } + + /** + * Raises the callback event. This method is required by {@link ICallbackEventHandler} + * interface. It will raise {@link onRowSelected OnRowSelected} event with a + * {@link TActiveTableRowEventParameter} containing the zero-based index of the + * TActiveTableRow. + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the event parameter + */ + public function raiseCallbackEvent($param) + { + $parameter = new TActiveTableRowEventParameter($this->getResponse(), $param->getCallbackParameter(), $this->getRowIndex()); + $this->onRowSelected($parameter); + } + + /** + * This method overrides parent's implementation and raises the control's + * callback event. This will fire the {@link onRowSelected OnRowSelected} + * event if an appropriate event handler is implemented. + * @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 TActiveTableCellEventParameter) + { + $this->raiseCallbackEvent($param); + return true; + } + else return false; + } + + /** + * This method is invoked when a callback is requested. The method raises + * 'OnRowSelected' 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 TActiveTableRowEventParameter event parameter to be passed to the event handlers + */ + public function onRowSelected($param) + { + $this->raiseEvent('OnRowSelected', $this, $param); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control if the event handler for the + * {@link onRowSelected OnRowSelected} event is set. + * @param THtmlWriter the writer responsible for rendering + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $writer->addAttribute('id', $this->getClientID()); + if ($this->hasEventHandler('OnRowSelected')) + $this->getActiveControl()->registerCallbackClientScript($this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * Renders and replaces the row'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 we update a TActiveTableRow on callback, we shouldn't update all childs, + // because the whole content will be replaced by the parent. + if ($this->getHasControls()) + { + foreach ($this->findControlsByType('IActiveControl', false) as $control) + $control->getActiveControl()->setEnableUpdate(false); + } + } + } + + /** + * Returns postback specifications for the table row. + * This method is used by framework and control developers. + * @return array parameters about how the row defines its postback behavior. + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } + + /** + * Returns the zero-based index of the TActiveTableRow within the {@link TTableRowCollection} + * of the parent {@link TTable} control. Raises a {@link TConfigurationException} if the row + * is no member of the row collection. + * @return integer the zero-based index of the row + */ + public function getRowIndex() + { + foreach ($this->getTable()->getRows() as $key => $row) + if ($row == $this) return $key; + throw new TConfigurationException('tactivetablerow_control_notincollection', get_class($this), $this->getUniqueID()); + } + + /** + * Returns the parent {@link TTable} control by looping through all parents until a {@link TTable} + * is found. Raises a {@link TConfigurationException} if no table control is found. + * @return TTable the parent table control + */ + public function getTable() + { + if ($this->_table === null) + { + $table = $this->getParent(); + while (!($table instanceof TTable) && $table !== null) + { + $table = $table->getParent(); + } + if ($table instanceof TTable) $this->_table = $table; + else throw new TConfigurationException('tactivetablerow_control_outoftable', get_class($this), $this->getUniqueID()); + } + return $this->_table; + } + +} + +/** + * TActiveTableRowEventParameter class. + * + * The TActiveTableRowEventParameter provides the parameter passed during the callback + * requestion 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. + * + * The {@link getSelectedRowIndex SelectedRowIndex} is a zero-based index of the + * TActiveTableRow , -1 if the row is not part of the row collection (this shouldn't + * happen though since an exception is thrown before). + * + * @author LANDWEHR Computer und Software GmbH <programmierung@landwehr-software.de> + * @package System.Web.UI.ActiveControls + * @since 3.1.9 + */ +class TActiveTableRowEventParameter extends TCallbackEventParameter +{ + /** + * @var integer the zero-based index of the row. + */ + private $_selectedRowIndex = -1; + + /** + * Creates a new TActiveTableRowEventParameter. + */ + public function __construct($response, $parameter, $index=-1) + { + parent::__construct($response, $parameter); + $this->_selectedRowIndex = $index; + } + + /** + * Returns the zero-based index of the {@link TActiveTableRow} within the + * {@link TTableRowCollection} of the parent {@link TTable} control. + * @return integer the zero-based index of the row. + */ + public function getSelectedRowIndex() + { + return $this->_selectedRowIndex; + } + +}
\ No newline at end of file diff --git a/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php b/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php new file mode 100644 index 0000000..f80b498 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TActiveTextBox.php @@ -0,0 +1,123 @@ +<?php +/** + * TActiveTextBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php b/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php new file mode 100644 index 0000000..e396e11 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TAutoComplete.php @@ -0,0 +1,438 @@ +<?php +/** + * TAutoComplete class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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)); + $repeater->setEmptyTemplate(new TAutoCompleteTemplate('<ul></ul>')); + $this->getControls()->add($repeater); + return $repeater; + } + + /** + * Renders the end tag and registers the needed javascript library. + */ + public function renderEndTag($writer) + { + $cs=$this->getPage()->getClientScript(); + $cs->registerPradoScript('autocomplete'); + 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> + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php new file mode 100644 index 0000000..01583eb --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TBaseActiveControl.php @@ -0,0 +1,394 @@ +<?php +/** + * TBaseActiveControl and TBaseActiveCallbackControl class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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> + * @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 + { + // TCheckBoxList overrides findControl() with a fake implementation + // but accepts a second parameter to use the standard one + $control=$this->getControl()->findControl($id, true); + } + + 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(); + // needed for TCallback + if(!isset($options['EventTarget'])) + $options['EventTarget'] = $this->getControl()->getUniqueID(); + 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/lib/prado/framework/Web/UI/ActiveControls/TCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TCallback.php new file mode 100644 index 0000000..1aae6ce --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallback.php @@ -0,0 +1,99 @@ +<?php +/** + * TCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php new file mode 100644 index 0000000..1f631f2 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientScript.php @@ -0,0 +1,826 @@ +<?php +/** + * TCallbackClientScript class file + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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 available 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> + * + * To call a specific jQuery method on an element, use the {@link jQuery} method: + * <code> + * // simple example: focus a textbox + * $this->getCallbackClient()->jQuery($myTextBox, 'focus'); + * + * // complex example: resize a textbox using an animation + * $this->getCallbackClient()->jQuery($myTextBox, 'animate', array( + * array( 'width' => '+=100', + * 'height' => '+=50' + * ), + * array('duration' => 1000) + * )); + * </code> + * + * To call a jQueryUI effect on an element, use the {@link juiEffect} method: + * <code> + * // simple example: focus a textbox + * $this->getCallbackClient()->juiEffect($myTextBox, 'highlight'); + * </code> + * + * In order to use the jQueryUI effects, the jqueryui script must be registered: + * <code> + * $this->getPage()->getClientScript()->registerPradoScript('jqueryui'); + * </code> + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @author Fabio Bas <ctrlaltca[at]gmail[dot]com> + * @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=array()) + { + if(!is_array($params)) + $params = array($params); + + if(count($params) > 0) + { + if ($params[0] instanceof ISurroundable) + $params[0] = $params[0]->getSurroundingTagID(); + elseif($params[0] instanceof TControl) + $params[0] = $params[0]->getClientID(); + } + $this->_actions->add(array($function => $params)); + } + + /** + * Executes a jQuery client-side method over an element. + * @param string control or element id + * @param string jQuery method name + * @param array list of arguments for the function + */ + public function jQuery($element, $method, $params=array()) + { + if ($element instanceof ISurroundable) + $element = $element->getSurroundingTagID(); + elseif($element instanceof TControl) + $element = $element->getClientID(); + + if(!is_array($params)) + $params = array($params); + + $this->_actions->add(array('Prado.Element.j' => array($element, $method, $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->jQuery($input, 'val', $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; + + // pass the ID to avoid getting the surrounding elements (ISurroundable) + if($control instanceof TControl) + $control = $control->getClientID(); + + $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->jQuery($control, 'trigger', 'click'); + } + + /** + * 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->jQuery($control, 'trigger', $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) + { + $this->jQuery($element, 'show'); + } + + /** + * Hides an element by changing its CSS display style to "none". + * @param TControl control element or element id + */ + public function hide($element) + { + $this->jQuery($element, 'hide'); + } + + /** + * Toggles the visibility of the element. + * @param TControl control element or element id + * @param string visual effect, such as, 'fade' or 'slide'. + * @param array additional options. + */ + public function toggle($element, $effect=null, $options=array()) + { + switch(strtolower($effect)) + { + case 'fade': + $method='fadeToggle'; + break; + case 'slide': + $method='slideToggle'; + break; + default: + $method='toggle'; + // avoid fancy effect by default + if(!array_key_exists('duration', $options)) + $options['duration']=0; + break; + } + $this->jQuery($element, $method, $options); + } + + /** + * Removes an element from the HTML page. + * @param TControl control element or element id + */ + public function remove($element) + { + $this->jQuery($element, 'remove'); + } + + /** + * 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) + { + $this->jQuery($element, 'html', $content); + } + + /** + * 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) + { + $this->jQuery($element, 'addClass', $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) + { + $this->jQuery($element, 'removeClass', $cssClass); + } + + /** + * Scroll the top of the browser viewing area to the location of the + * element. + * + * @param TControl control element or element id + * @param array additional options: 'duration' in ms, 'offset' from the top in pixels + */ + public function scrollTo($element, $options=array()) + { + $this->callClientFunction('Prado.Element.scrollTo', array($element, $options)); + } + + /** + * Focus on a particular element. + * @param TControl control element or element id. + */ + public function focus($element) + { + $this->jQuery($element, 'trigger', 'focus'); + } + + /** + * 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) + { + $this->jQuery($element, 'css', array($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) + { + $this->jQuery($element, 'append', $content); + } + + /** + * 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) + { + $this->jQuery($element, 'prepend', $content); + } + + /** + * 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) + { + $this->jQuery($element, 'after', $content); + } + + /** + * 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) + { + $this->jQuery($element, 'before', $content); + } + + /** + * 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 boolean whether to fully replace the element or just its inner content. + * @see insertAbout + * @see insertBelow + * @see insertBefore + * @see insertAfter + */ + protected function replace($element, $content, $self) + { + if($content instanceof TControl) + { + $boundary = $this->getRenderedContentBoundary($content); + $content = null; + } + else if($content instanceof THtmlWriter) + { + $boundary = $this->getResponseContentBoundary($content); + $content = null; + } + else + $boundary = null; + + $this->callClientFunction('Prado.Element.replace', array($element, $content, $boundary, $self)); + } + + /** + * 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. + * @param boolean whether to fully replace the element or just its inner content, defaults to true. + */ + public function replaceContent($element, $content, $self=true) + { + $this->replace($element, $content, $self); + } + + + /** + * Evaluate a block of javascript enclosed in a boundary. + * @param THtmlWriter writer for the content. + */ + public function evaluateScript($writer) + { + if($writer instanceof THtmlWriter) + { + $boundary = $this->getResponseContentBoundary($writer); + $content = null; + } else { + $boundary = null; + $content = $writer; + } + + $this->callClientFunction('Prado.Element.evaluateScript', array($content, $boundary)); + } + + /** + * 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); + } + elseif($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; + } + + /* VISUAL EFFECTS */ + + /** + * 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=array()) + { + $this->jQuery($element, $type, $options); + } + + /* BASIC EFFECTS (JQUERY CORE) */ + + /** + * Visual Effect: Gradually make the element appear. + * This effect doesn't need jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fadeIn($element, $options=array()) + { + $this->visualEffect('fadeIn', $element, $options); + } + + /** + * Visual Effect: Gradually fade the element. + * This effect doesn't need jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fadeOut($element, $options=array()) + { + $this->visualEffect('fadeOut', $element, $options); + } + + /** + * Set the opacity on a html element or control. + * This effect doesn't need jQueryUI. + * @param TControl control element or element id + * @param float opacity value between 1 and 0 + */ + public function fadeTo($element, $value, $duration=500) + { + $value = TPropertyValue::ensureFloat($value); + $this->visualEffect('fadeTo', $element, array($duration, $value)); + } + + /** + * Visual Effect: Slide down. + * This effect doesn't need jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function slideDown($element, $options=array()) + { + $this->visualEffect('slideDown', $element, $options); + } + + /** + * Visual Effect: Slide up. + * This effect doesn't need jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function slideUp($element, $options=array()) + { + $this->visualEffect('slideUp', $element, $options); + } + + /* OLD METHODS, DEPRECATED, BACKWARDS-COMPATIBILITY */ + + /** + * Alias of fadeIn() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function appear($element, $options=array()) + { + $this->fadeIn($element, $options); + } + + /** + * Alias of fadeOut() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fade($element, $options=array()) + { + $this->fadeOut($element, $options); + } + + /** + * Alias of fadeTo() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param float opacity value between 1 and 0 + */ + public function setOpacity($element, $value) + { + $this->fadeTo($element, $value); + } + + /* JQUERY UI EFFECTS */ + + /** + * Add a jQuery-ui effect the element. + * This method needs jQueryUI. + * @param string visual effect function name. + * @param TControl control element or element id + * @param array effect options. + */ + public function juiEffect($element, $effect, $options=array()) + { + $options['effect']=$effect; + $this->jQuery($element, 'effect', array($options)); + } + + /** + * Visual Effect: Blind. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function blind($element, $options=array()) + { + $this->juiEffect($element, 'blind', $options); + } + + /** + * Visual Effect: Drop out. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function drop($element, $options=array()) + { + $this->juiEffect($element, 'drop', $options); + } + + /** + * Visual Effect: Fold. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function fold($element, $options=array()) + { + $this->juiEffect($element, 'fold', $options); + } + + /** + * Visual Effect: Gradually make an element grow to a predetermined size. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function size($element, $options=array()) + { + $this->juiEffect($element, 'size', $options); + } + + /** + * Visual Effect: Gradually grow and fade the element. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function puff($element, $options=array()) + { + $this->juiEffect($element, 'puff', $options); + } + + /** + * Visual Effect: Pulsate. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function pulsate($element, $options=array()) + { + $this->juiEffect($element, 'pulsate', $options); + } + + /** + * Visual Effect: Shake the element. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function shake($element, $options=array()) + { + $this->juiEffect($element, 'shake', $options); + } + + /** + * Visual Effect: Scale the element. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function scale($element, $options=array()) + { + $this->juiEffect($element, 'scale', $options); + } + + /** + * Visual Effect: High light the element for about 2 seconds. + * This effect needs jQueryUI. + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function highlight($element, $options=array()) + { + $this->juiEffect($element, 'highlight', $options); + } + + /* jui - OLD METHODS, DEPRECATED, BACKWARDS-COMPATIBILITY */ + + /** + * Alias of blind(), presets the direction to 'down' + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function blindDown($element, $options=array()) + { + $options['direction']='down'; + $this->blind($element, $options); + } + + /** + * Alias of blind(), presets the direction to 'up' + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function blindUp($element, $options=array()) + { + $options['direction']='up'; + $this->blind($element, $options); + } + + /** + * Alias of drop() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function dropOut($element, $options=array()) + { + $this->drop($element, $options); + } + + /** + * Alias of size() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function grow($element, $options=array()) + { + $this->size($element, $options); + } + + /** + * Alias of scale() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function shrink($element, $options=array()) + { + $options['percent']=0; + $this->scale($element, $options); + } + + /** + * Alias of scale() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function squish($element, $options=array()) + { + $options['origin']=array('top', 'left'); + $options['percent']=0; + $this->scale($element, $options); + } + + /** + * Alias of scale() + * @deprecated since 3.4 + * @param TControl control element or element id + * @param array visual effect key-value pair options. + */ + public function switchOff($element, $options=array()) + { + $options['direction']='vertical'; + $options['percent']=0; + $this->scale($element, $options); + } + +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php new file mode 100644 index 0000000..874aeb4 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackClientSide.php @@ -0,0 +1,320 @@ +<?php +/** + * TCallbackClientSide class file + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php new file mode 100644 index 0000000..9306aec --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackEventParameter.php @@ -0,0 +1,86 @@ +<?php +/** + * TCallbackEventParameter class file. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php new file mode 100644 index 0000000..e79561d --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackOptions.php @@ -0,0 +1,51 @@ +<?php +/** + * TCallbackOptions component class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php b/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php new file mode 100755 index 0000000..4a1c41b --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TCallbackResponseAdapter.php @@ -0,0 +1,159 @@ +<?php +/** + * TCallbackResponseAdapter and TCallbackResponseWriter class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TCallbackResponseAdapter alters the THttpResponse's outputs. + * + * A TCallbackResponseWriter is used instead of the TTextWrite when + * createHtmlWriter is called. Each call to createHtmlWriter will create + * a new TCallbackResponseWriter. When flushContent() is called each + * instance of TCallbackResponseWriter's content is flushed. + * + * The callback response data can be set using the {@link setResponseData ResponseData} + * property. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackResponseAdapter extends THttpResponseAdapter +{ + /** + * @var TCallbackResponseWriter[] list of writers. + */ + private $_writers=array(); + /** + * @var mixed callback response data. + */ + private $_data; + + private $_redirectUrl=null; + + /** + * Returns a new instance of THtmlWriter. + * An instance of TCallbackResponseWriter is created to hold the content. + * @param string writer class name. + * @param THttpResponse http response handler. + */ + public function createNewHtmlWriter($type,$response) + { + $writer = new TCallbackResponseWriter(); + $this->_writers[] = $writer; + return parent::createNewHtmlWriter($type,$writer); + } + + /** + * Flushes the contents in the writers. + */ + public function flushContent() + { + foreach($this->_writers as $writer) + echo $writer->flush(); + parent::flushContent(); + } + + /** + * @param mixed callback response data. + */ + public function setResponseData($data) + { + $this->_data = $data; + } + + /** + * @return mixed callback response data. + */ + public function getResponseData() + { + return $this->_data; + } + + /** + * Delay the redirect until we process the rest of the page. + * @param string new url to redirect to. + */ + public function httpRedirect($url) + { + if($url[0]==='/') + $url=$this->getRequest()->getBaseUrl().$url; + $this->_redirectUrl=str_replace('&','&',$url); + } + + /** + * @return string new url for callback response to redirect to. + */ + public function getRedirectedUrl() + { + return $this->_redirectUrl; + } +} + +/** + * TCallbackResponseWriter class. + * + * TCallbackResponseWriter class enclosed a chunck of content within a + * html comment boundary. This allows multiple chuncks of content to return + * in the callback response and update multiple HTML elements. + * + * The {@link setBoundary Boundary} property sets boundary identifier in the + * HTML comment that forms the boundary. By default, the boundary identifier + * is generated using microtime. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TCallbackResponseWriter extends TTextWriter +{ + /** + * @var string boundary ID + */ + private $_boundary; + + /** + * Constructor. Generates unique boundary ID using microtime. + */ + public function __construct() + { + parent::__construct(); + $this->_boundary = sprintf('%x',crc32(uniqid(null, true))); + } + + /** + * @return string boundary identifier. + */ + public function getBoundary() + { + return $this->_boundary; + } + + /** + * @param string boundary identifier. + */ + public function setBoundary($value) + { + $this->_boundary = $value; + } + + /** + * Returns the text content wrapped within a HTML comment with boundary + * identifier as its comment content. + * @return string text content chunck. + */ + public function flush() + { + $content = parent::flush(); + if(empty($content)) + return ""; + return '<!--'.$this->getBoundary().'-->'.$content.'<!--//'.$this->getBoundary().'-->'; + } +} + diff --git a/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php b/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php new file mode 100755 index 0000000..3f6008b --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TDraggable.php @@ -0,0 +1,246 @@ +<?php +/** + * TDraggable class file + * + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * TDraggable is a control which can be dragged + * + * This control will make "draggable" control. + * Properties : + * + * <b>{@link setGhosting Ghosting}</b> : If set to "Ghosting" or "True", the dragged element will be cloned, and the clone will be dragged. + * If set to "SuperGhosting", the element will be cloned, and attached to body, so it can be dragged outside of its parent. + * If set to "None" of "False" (default), the element itself is dragged + * <b>{@link setRevert Revert}</b>: Set to True if you want your dragged element to revert to its initial position if not dropped on a valid area. + * <b>{@link setConstraint Constraint}</b>: Set this to Horizontal or Vertical if you want to constraint your move in one direction. + * <b>{@link setHandle Handle}</b>: + * + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDraggable extends TPanel +{ + /** + * Set the handle id or css class + * @param string + */ + public function setHandle ($value) + { + $this->setViewState('DragHandle', TPropertyValue::ensureString($value), null); + } + + /** + * Get the handle id or css class + * @return string + */ + public function getHandle () + { + return $this->getViewState('DragHandle', null); + } + + /** + * Determine if draggable element should revert to it orginal position + * upon release in an non-droppable container. + * Since 3.2, Revert property can be set to one of the value of {@link TDraggableRevertOption} enumeration. + * o 'True' or 'Revert' : The draggable will revert to it's original position + * o 'False' or 'None' : The draggable won't revert to it's original position + * o 'Failure' : The draggable will only revert if it's dropped on a non droppable area + * @return TDraggableRevertOption true to revert + */ + public function getRevert() + { + return $this->getViewState('Revert', TDraggableRevertOptions::Revert); + } + + /** + * Sets whether the draggable element should revert to it orginal position + * upon release in an non-droppable container. + * Since 3.2, Revert property can be set to one of the value of {@link TDraggableRevertOption} enumeration. + * o 'True' or 'Revert' : The draggable will revert to it's original position + * o 'False' or 'None' : The draggable won't revert to it's original position + * o 'Failure' : The draggable will only revert if it's dropped on a non droppable area + * @param boolean true to revert + */ + public function setRevert($value) + { + if (strcasecmp($value,'true')==0 || $value===true) + $value=TDraggableRevertOptions::Revert; + elseif (strcasecmp($value,'false')==0 || $value===false) + $value=TDraggableRevertOptions::None; + $this->setViewState('Revert', TPropertyValue::ensureEnum($value, 'TDraggableRevertOptions'), true); + } + + /** + * Determine if the element should be cloned when dragged + * If true, Clones the element and drags the clone, leaving the original in place until the clone is dropped. + * Defaults to false + * Since 3.2, Ghosting can be set to one of the value of {@link TDraggableGhostingOptions} enumeration. + * o "True" or "Ghosting" means standard pre-3.2 ghosting mechanism + * o "SuperGhosting" use the Superghosting patch by Christopher Williams, which allow elements to be dragged from an + * scrollable list + * o "False" or "None" means no Ghosting options + * + * @return TDraggableGhostingOption to clone the element + */ + public function getGhosting () + { + return $this->getViewState('Ghosting', TDraggableGhostingOptions::None); + } + + /** + * Sets wether the element should be cloned when dragged + * If true, Clones the element and drags the clone, leaving the original in place until the clone is dropped. + * Defaults to false + * + * Since 3.2, Ghosting can be set to one of the value of {@link TDraggableGhostingOptions} enumeration. + * o "True" or "Ghosting" means standard pre-3.2 ghosting mechanism + * o "SuperGhosting" use the Superghosting patch by Christopher Williams, which allow elements to be dragged from an + * scrollable list + * o "False" or "None" means no Ghosting options + * + */ + public function setGhosting ($value) + { + if (strcasecmp($value,'true')==0 || $value===true) + $value=TDraggableGhostingOptions::Ghosting; + elseif (strcasecmp($value,'false')==0 || $value===false) + $value=TDraggableGhostingOptions::None; + $this->setViewState('Ghosting', TPropertyValue::ensureEnum($value, 'TDraggableGhostingOptions'), TDraggableGhostingOptions::None); + } + + /** + * Determine if the element should be constrainted in one direction or not + * @return CDraggableConstraint + */ + public function getConstraint() + { + return $this->getViewState('Constraint', TDraggableConstraint::None); + } + + /** + * Set wether the element should be constrainted in one direction + * @param CDraggableConstraint + */ + public function setConstraint($value) + { + $this->setViewState('Constraint', TPropertyValue::ensureEnum($value, 'TDraggableConstraint'), TDraggableConstraint::None); + } + + /** + * Registers clientscripts + * + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + } + + /** + * Ensure that the ID attribute is rendered and registers the javascript code + * for initializing the active control. + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + + $cs=$this->getPage()->getClientScript(); + if ($this->getGhosting()==TDraggableGhostingOptions::SuperGhosting) + $cs->registerPradoScript('dragdropextra'); + else + $cs->registerPradoScript('dragdrop'); + $writer->addAttribute('id',$this->getClientID()); + $options=TJavascript::encode($this->getPostBackOptions()); + $class=$this->getClientClassName(); + $code="new {$class}('{$this->getClientId()}', {$options}) "; + $cs->registerEndScript(sprintf('%08X', crc32($code)), $code); + } + + /** + * 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 'Draggable'; + } + + /** + * Gets the post back options for this textbox. + * @return array + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + + if (($handle=$this->getHandle())!== null) $options['handle']=$handle; + if (($revert=$this->getRevert())===TDraggableRevertOptions::None) + $options['revert']=false; + elseif ($revert==TDraggableRevertOptions::Revert) + $options['revert']=true; + else + $options['revert']=strtolower($revert); + if (($constraint=$this->getConstraint())!==TDraggableConstraint::None) $options['constraint']=strtolower($constraint); + switch ($this->getGhosting()) + { + case TDraggableGhostingOptions::SuperGhosting: + $options['superghosting']=true; + break; + case TDraggableGhostingOptions::Ghosting: + $options['ghosting']=true; + break; + } + + return $options; + } + +} + +/** + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDraggableConstraint extends TEnumerable +{ + const None='None'; + const Horizontal='Horizontal'; + const Vertical='Vertical'; +} + +/** + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDraggableGhostingOptions extends TEnumerable +{ + const None='None'; + const Ghosting='Ghosting'; + const SuperGhosting='SuperGhosting'; +} + +/** + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDraggableRevertOptions extends TEnumerable +{ + const None='None'; + const Revert='Revert'; + const Failure='Failure'; +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php b/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php new file mode 100755 index 0000000..49eb0db --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TDropContainer.php @@ -0,0 +1,317 @@ +<?php +/** + * TDropContainer class file + * + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active control adapter. + */ +Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter'); +/** + * Load active panel. + */ +Prado::using('System.Web.UI.ActiveControls.TActivePanel'); + + +/** + * TDropContainer is a panel where TDraggable controls can be dropped. + * When a TDraggable component is dropped into a TDropContainer, the {@link OnDrop OnDrop} event is raised. + * The {@link TDropContainerEventParameter} param will contain the dropped control. + * + * Properties : + * + * <b>{@link setAcceptCssClass AcceptCssClass}</b> : a coma delimited classname of elements that the drop container can accept. + * <b>{@link setHoverCssClass HoverCssClass}</b>: CSS classname of the container when a draggable element hovers over the container. + * + * Events: + * + * <b>{@link OnDrop OnDrop}</b> : raised when a TDraggable control is dropped. The dropped control id is encapsulated in the event parameter, + * as well as mouse coordinates and key modifiers status + * + * + * @author Christophe BOULAIN (Christophe.Boulain@gmail.com) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDropContainer extends TPanel implements IActiveControl, ICallbackEventHandler +{ + private $_container=null; + + /** + * 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(); + } + + /** + * @return TCallbackClientSide client side request options. + */ + public function getClientSide() + { + return $this->getAdapter()->getBaseActiveControl()->getClientSide(); + } + + /** + * Gets the Css class name that this container can accept. + * @return string + */ + public function getAcceptCssClass() + { + return $this->getViewState('Accepts', ''); + } + + /** + * Sets the Css class name that this container can accept. + * @param string comma delimited css class names. + */ + public function setAcceptCssClass($value) + { + $this->setViewState('Accepts', TPropertyValue::ensureArray($value), ''); + } + + /** + * Sets the Css class name used when a draggble element is hovering + * over this container. + * @param string css class name during draggable hover. + */ + public function setHoverCssClass($value) + { + $this->setViewState('HoverClass', $value, ''); + } + + /** + * Gets the Css class name used when a draggble element is hovering + * over this container. + * @return string css class name during draggable hover. + */ + public function getHoverCssClass() + { + return $this->getViewState('HoverClass', ''); + } + + + /** + * Raises callback event. This method is required bu {@link ICallbackEventHandler} + * interface. + * It raises the {@link onDrop OnDrop} event, then, the {@link onCallback OnCallback} event + * This method is mainly used by framework and control developers. + * @param TCallbackEventParameter the parameter associated with the callback event + */ + public function raiseCallbackEvent($param) + { + $this->onDrop($param->getCallbackParameter()); + $this->onCallback($param); + } + + /** + * Raises the onDrop event. + * The drop parameters are encapsulated into a {@link TDropContainerEventParameter} + * + * @param object $dropControlId + */ + public function onDrop ($dropParams) + { + $this->raiseEvent('OnDrop', $this, new TDropContainerEventParameter ($dropParams)); + + } + + /** + * 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 post back options for this textbox. + * @return array + */ + protected function getPostBackOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + + $options['accept'] = $this->getAcceptCssClass(); + $options['hoverclass'] = $this->getHoverCssClass(); + return $options; + } + + /** + * 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.DropContainer'; + } + + /** + * Registers clientscripts + * + * This method overrides the parent implementation and is invoked before render. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + } + + /** + * 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->getPage()->getClientScript()->registerPradoScript('dragdrop'); + $this->getActiveControl()->registerCallbackClientScript( + $this->getClientClassName(), $this->getPostBackOptions()); + } + + /** + * Creates child control + * Override parent implementation to create a container which will contain all + * child controls. This container will be a TActivePanel, in order to allow user + * to update its content on callback. + */ + public function createChildControls () + { + if ($this->_container===null) + { + $this->_container=Prado::CreateComponent('System.Web.UI.ActiveControls.TActivePanel'); + $this->_container->setId($this->getId(false).'_content'); + parent::getControls()->add($this->_container); + } + } + + /** + * Override parent implementation to return the container control collection. + * + * @return TControlCollection + */ + public function getControls() + { + $this->ensureChildControls(); + return $this->_container->getControls(); + } + + /** + * 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->_container,$writer); + } + else + { + $this->getPage()->getAdapter()->registerControlToRender($this->_container,$writer); + } + } + +} + +/** + * TDropContainerEventParameter class + * + * TDropContainerEventParameter encapsulate the parameter + * data for <b>OnDrop</b> event of TDropContainer components + * + * @author Christophe BOULAIN (Christophe.Boulain@ceram.fr) + * @copyright Copyright © 2008, PradoSoft + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ +class TDropContainerEventParameter extends TEventParameter +{ + private $_dragElementId; + private $_screenX; + private $_screenY; + private $_offsetX; + private $_offsetY; + private $_clientX; + private $_clientY; + private $_shiftKey; + private $_ctrlKey; + private $_altKey; + + public function __construct($dropParams) + { + $this->_dragElementId = $dropParams->DragElementID; + $this->_screenX = $dropParams->ScreenX; + $this->_screenY = $dropParams->ScreenY; + $this->_offsetX = isset($dropParams->OffsetX) ? $dropParams->OffsetX : false; + $this->_offsetY = isset($dropParams->OffsetY) ? $dropParams->OffsetY : false; + $this->_clientX = $dropParams->ClientX; + $this->_clientY = $dropParams->ClientY; + $this->_shiftKey = TPropertyValue::ensureBoolean($dropParams->ShiftKey); + $this->_ctrlKey = TPropertyValue::ensureBoolean($dropParams->CtrlKey); + $this->_altKey = TPropertyValue::ensureBoolean($dropParams->AltKey); + } + + public function getDragElementId() { return $this->_dragElementId; } + public function getScreenX() { return $this->_screenX; } + public function getScreenY() { return $this->_screenY; } + public function getOffsetX() { return $this->_offsetX; } + public function geOffsetY() { return $this->_offsetY; } + public function getClientX() { return $this->_clientX; } + public function getClientY() { return $this->_clientY; } + public function getShiftKey() { return $this->_shiftKey; } + public function getCtrlKey() { return $this->_ctrlKey; } + public function getAltKey() { return $this->_altKey; } + + /** + * GetDroppedControl + * + * Compatibility method to get the dropped control + * @return TControl dropped control, or null if not found + */ + public function getDroppedControl () + { + $control=null; + $service=prado::getApplication()->getService(); + if ($service instanceof TPageService) + { + // Find the control + // Warning, this will not work if you have a '_' in your control Id ! + $dropControlId=str_replace(TControl::CLIENT_ID_SEPARATOR,TControl::ID_SEPARATOR,$this->_dragElementId); + $control=$service->getRequestedPage()->findControl($dropControlId); + } + return $control; + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php new file mode 100644 index 0000000..d990e09 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php @@ -0,0 +1,93 @@ +<?php +/** + * TEventTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php new file mode 100644 index 0000000..d267729 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TInPlaceTextBox.php @@ -0,0 +1,288 @@ +<?php +/** + * TInPlaceTextBox class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php new file mode 100644 index 0000000..b643de4 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TTimeTriggeredCallback.php @@ -0,0 +1,126 @@ +<?php +/** + * TTimeTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web.UI.ActiveControls + */ + +/** + * Load active callback control. + */ +Prado::using('System.Web.UI.ActiveControls.TCallback'); + +/** + * TTimeTriggeredCallback class. + * + * TTimeTriggeredCallback sends callback request every {@link setInterval Interval} seconds. + * Upon each callback request, the {@link onCallback OnCallback} event is raised. + * + * The timer can be started by calling {@link startTimer()} and stopped using + * {@link stopTimer()}. The timer can be automatically started when + * {@link setStartTimerOnLoad StartTimerOnLoad} is true. + * + * @author Wei Zhuo <weizhuo[at]gmail[dot]com> + * @package System.Web.UI.ActiveControls + * @since 3.1 + */ +class TTimeTriggeredCallback extends TCallback +{ + /** + * @return float seconds between callback requests. Default is 1 second. + */ + public function getInterval() + { + return $this->getViewState('Interval', 1); + } + + /** + * @param float seconds between callback requests, must be a positive number, default is 1 second. + */ + public function setInterval($value) + { + $interval = TPropertyValue::ensureFloat($value); + if($interval <= 0) + throw new TConfigurationException('callback_interval_be_positive', $this->getID()); + $this->setViewState('Interval', $interval, 1); + if ($this->getActiveControl()->canUpdateClientSide()){ + $client = $this->getPage()->getCallbackClient(); + $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.setTimerInterval', array($this, $interval)); + } + } + + /** + * Registers the javascript code to start the timer. + */ + public function startTimer() + { + $client = $this->getPage()->getCallbackClient(); + $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.start', array($this)); + } + + /** + * Registers the javascript code to stop the timer. + */ + public function stopTimer() + { + $client = $this->getPage()->getCallbackClient(); + $client->callClientFunction('Prado.WebUI.TTimeTriggeredCallback.stop', array($this)); + } + + /** + * @param boolean true to start the timer when page loads. + */ + public function setStartTimerOnLoad($value) + { + $this->setViewState('StartTimerOnLoad', + TPropertyValue::ensureBoolean($value), false); + } + + /** + * @return boolean true to start the timer when page loads. + */ + public function getStartTimerOnLoad() + { + return $this->getViewState('StartTimerOnLoad', false); + } + + /** + * @return array list of timer options for client-side. + */ + protected function getTriggerOptions() + { + $options['ID'] = $this->getClientID(); + $options['EventTarget']= $this->getUniqueID(); + $options['Interval'] = $this->getInterval(); + 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()); + if($this->getStartTimerOnLoad()){ + $id = $this->getClientID(); + $code = "Prado.WebUI.TTimeTriggeredCallback.start('{$id}');"; + $cs = $this->getPage()->getClientScript(); + $cs->registerEndScript("{$id}:start", $code); + } + } + + /** + * @return string corresponding javascript class name for TTimeTriggeredCallback. + */ + protected function getClientClassName() + { + return 'Prado.WebUI.TTimeTriggeredCallback'; + } +} diff --git a/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php new file mode 100644 index 0000000..7675bc8 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TTriggeredCallback.php @@ -0,0 +1,69 @@ +<?php +/** + * TTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php b/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php new file mode 100644 index 0000000..87a7d60 --- /dev/null +++ b/lib/prado/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php @@ -0,0 +1,118 @@ +<?php +/** + * TValueTriggeredCallback class file. + * + * @author Wei Zhuo <weizhuo[at]gamil[dot]com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @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> + * @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'; + } +} |