From 903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 Mon Sep 17 00:00:00 2001
From: ctrlaltca <>
Date: Thu, 12 Jul 2012 11:21:01 +0000
Subject: standardize the use of unix eol; use svn properties to enforce native
eol
---
framework/Web/UI/ActiveControls/TActiveButton.php | 264 +-
.../Web/UI/ActiveControls/TActiveClientScript.php | 164 +-
.../UI/ActiveControls/TActiveControlAdapter.php | 1150 ++---
.../UI/ActiveControls/TActiveCustomValidator.php | 530 +--
framework/Web/UI/ActiveControls/TActiveLabel.php | 2 +-
.../Web/UI/ActiveControls/TActivePageAdapter.php | 802 ++--
framework/Web/UI/ActiveControls/TActivePanel.php | 200 +-
.../Web/UI/ActiveControls/TActiveRatingList.php | 266 +-
framework/Web/UI/ActiveControls/TActiveTextBox.php | 250 +-
framework/Web/UI/ActiveControls/TAutoComplete.php | 880 ++--
.../Web/UI/ActiveControls/TBaseActiveControl.php | 784 ++--
framework/Web/UI/ActiveControls/TCallback.php | 202 +-
.../UI/ActiveControls/TCallbackClientScript.php | 1410 +++---
.../Web/UI/ActiveControls/TCallbackClientSide.php | 644 +--
.../UI/ActiveControls/TCallbackEventParameter.php | 174 +-
.../Web/UI/ActiveControls/TCallbackOptions.php | 106 +-
.../UI/ActiveControls/TEventTriggeredCallback.php | 190 +-
.../Web/UI/ActiveControls/TInPlaceTextBox.php | 580 +--
.../Web/UI/ActiveControls/TTriggeredCallback.php | 142 +-
.../UI/ActiveControls/TValueTriggeredCallback.php | 240 +-
framework/Web/UI/TCachePageStatePersister.php | 400 +-
framework/Web/UI/TCompositeControl.php | 74 +-
framework/Web/UI/TControl.php | 4790 ++++++++++----------
framework/Web/UI/TControlAdapter.php | 286 +-
framework/Web/UI/TForm.php | 342 +-
framework/Web/UI/THtmlWriter.php | 458 +-
framework/Web/UI/TPage.php | 2682 +++++------
framework/Web/UI/TPageStatePersister.php | 140 +-
framework/Web/UI/TSessionPageStatePersister.php | 260 +-
framework/Web/UI/TTemplateControl.php | 484 +-
framework/Web/UI/TTemplateManager.php | 2150 ++++-----
framework/Web/UI/TThemeManager.php | 1034 ++---
framework/Web/UI/WebControls/TAccordion.php | 1488 +++---
framework/Web/UI/WebControls/TBaseDataList.php | 378 +-
framework/Web/UI/WebControls/TBoundColumn.php | 498 +-
framework/Web/UI/WebControls/TBulletedList.php | 982 ++--
framework/Web/UI/WebControls/TButton.php | 734 +--
framework/Web/UI/WebControls/TButtonColumn.php | 554 +--
framework/Web/UI/WebControls/TCaptcha.php | 990 ++--
framework/Web/UI/WebControls/TCaptchaValidator.php | 254 +-
framework/Web/UI/WebControls/TCheckBox.php | 1026 ++---
framework/Web/UI/WebControls/TCheckBoxColumn.php | 244 +-
framework/Web/UI/WebControls/TCheckBoxList.php | 998 ++--
framework/Web/UI/WebControls/TColorPicker.php | 580 +--
framework/Web/UI/WebControls/TCompareValidator.php | 528 +--
framework/Web/UI/WebControls/TConditional.php | 284 +-
framework/Web/UI/WebControls/TContent.php | 92 +-
.../Web/UI/WebControls/TContentPlaceHolder.php | 94 +-
framework/Web/UI/WebControls/TCustomValidator.php | 414 +-
framework/Web/UI/WebControls/TDataBoundControl.php | 1174 ++---
framework/Web/UI/WebControls/TDataGrid.php | 4516 +++++++++---------
framework/Web/UI/WebControls/TDataGridColumn.php | 1134 ++---
.../Web/UI/WebControls/TDataGridItemRenderer.php | 58 +-
.../Web/UI/WebControls/TDataGridPagerStyle.php | 510 +--
framework/Web/UI/WebControls/TDataList.php | 3530 +++++++--------
.../Web/UI/WebControls/TDataListItemRenderer.php | 342 +-
framework/Web/UI/WebControls/TDataRenderer.php | 102 +-
.../Web/UI/WebControls/TDataSourceControl.php | 234 +-
framework/Web/UI/WebControls/TDataSourceView.php | 410 +-
.../Web/UI/WebControls/TDataTypeValidator.php | 280 +-
framework/Web/UI/WebControls/TDatePicker.php | 1986 ++++----
framework/Web/UI/WebControls/TDropDownList.php | 308 +-
.../Web/UI/WebControls/TDropDownListColumn.php | 640 +--
.../Web/UI/WebControls/TEditCommandColumn.php | 528 +--
.../Web/UI/WebControls/TEmailAddressValidator.php | 192 +-
framework/Web/UI/WebControls/TExpression.php | 122 +-
framework/Web/UI/WebControls/TFileUpload.php | 562 +--
framework/Web/UI/WebControls/TFlushOutput.php | 170 +-
framework/Web/UI/WebControls/TFont.php | 634 +--
framework/Web/UI/WebControls/THead.php | 754 +--
framework/Web/UI/WebControls/THiddenField.php | 410 +-
framework/Web/UI/WebControls/THtmlElement.php | 136 +-
framework/Web/UI/WebControls/THyperLink.php | 454 +-
framework/Web/UI/WebControls/THyperLinkColumn.php | 546 +--
framework/Web/UI/WebControls/TImage.php | 312 +-
framework/Web/UI/WebControls/TImageButton.php | 882 ++--
framework/Web/UI/WebControls/TImageMap.php | 1672 +++----
framework/Web/UI/WebControls/TItemDataRenderer.php | 164 +-
framework/Web/UI/WebControls/TJavascriptLogger.php | 186 +-
framework/Web/UI/WebControls/TKeyboard.php | 378 +-
framework/Web/UI/WebControls/TLabel.php | 306 +-
framework/Web/UI/WebControls/TLinkButton.php | 666 +--
framework/Web/UI/WebControls/TListBox.php | 486 +-
framework/Web/UI/WebControls/TListControl.php | 1846 ++++----
.../Web/UI/WebControls/TListControlValidator.php | 448 +-
framework/Web/UI/WebControls/TListItem.php | 366 +-
framework/Web/UI/WebControls/TLiteral.php | 222 +-
framework/Web/UI/WebControls/TLiteralColumn.php | 306 +-
framework/Web/UI/WebControls/TMarkdown.php | 148 +-
framework/Web/UI/WebControls/TMultiView.php | 756 +--
framework/Web/UI/WebControls/TOutputCache.php | 1240 ++---
framework/Web/UI/WebControls/TPager.php | 1582 +++----
framework/Web/UI/WebControls/TPanel.php | 492 +-
framework/Web/UI/WebControls/TPanelStyle.php | 554 +--
framework/Web/UI/WebControls/TPlaceHolder.php | 54 +-
framework/Web/UI/WebControls/TRadioButton.php | 638 +--
framework/Web/UI/WebControls/TRangeValidator.php | 716 +--
framework/Web/UI/WebControls/TRatingList.php | 718 +--
framework/Web/UI/WebControls/TReCaptcha.php | 464 +-
.../Web/UI/WebControls/TReCaptchaValidator.php | 244 +-
.../UI/WebControls/TRegularExpressionValidator.php | 288 +-
framework/Web/UI/WebControls/TRepeatInfo.php | 1118 ++---
framework/Web/UI/WebControls/TRepeater.php | 2048 ++++-----
.../Web/UI/WebControls/TRepeaterItemRenderer.php | 98 +-
.../Web/UI/WebControls/TRequiredFieldValidator.php | 274 +-
framework/Web/UI/WebControls/TSafeHtml.php | 170 +-
framework/Web/UI/WebControls/TSlider.php | 1148 ++---
framework/Web/UI/WebControls/TStatements.php | 124 +-
framework/Web/UI/WebControls/TStyle.php | 1786 ++++----
framework/Web/UI/WebControls/TTable.php | 818 ++--
framework/Web/UI/WebControls/TTableCell.php | 442 +-
framework/Web/UI/WebControls/TTableFooterRow.php | 92 +-
framework/Web/UI/WebControls/TTableHeaderCell.php | 246 +-
framework/Web/UI/WebControls/TTableHeaderRow.php | 92 +-
framework/Web/UI/WebControls/TTableRow.php | 414 +-
framework/Web/UI/WebControls/TTemplateColumn.php | 510 +--
framework/Web/UI/WebControls/TTextBox.php | 1304 +++---
framework/Web/UI/WebControls/TTextProcessor.php | 170 +-
.../Web/UI/WebControls/TValidationSummary.php | 1072 ++---
.../Web/UI/WebControls/TWebControlAdapter.php | 140 +-
framework/Web/UI/WebControls/TWizard.php | 4290 +++++++++---------
.../WebControls/TWizardNavigationButtonStyle.php | 308 +-
framework/Web/UI/WebControls/assets/captcha.php | 448 +-
123 files changed, 42598 insertions(+), 42598 deletions(-)
(limited to 'framework/Web/UI')
diff --git a/framework/Web/UI/ActiveControls/TActiveButton.php b/framework/Web/UI/ActiveControls/TActiveButton.php
index aaa10168..15b33692 100644
--- a/framework/Web/UI/ActiveControls/TActiveButton.php
+++ b/framework/Web/UI/ActiveControls/TActiveButton.php
@@ -1,132 +1,132 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveButton is the active control counter part to TButton.
- *
- * When a TActiveButton is clicked, rather than a normal post back request a
- * callback request is initiated.
- *
- * The {@link onCallback OnCallback} event is raised during a callback request
- * and it is raise after 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
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
- * is true, it will invoke the page's {@link TPage::validate validate}
- * method first. It will raise {@link onClick OnClick} event first
- * and then the {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->raisePostBackEvent($param);
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Updates the button text on the client-side if the
- * {@link setEnableUpdate EnableUpdate} property is set to true.
- * @param string caption of the button
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveButton';
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveButton is the active control counter part to TButton.
+ *
+ * When a TActiveButton is clicked, rather than a normal post back request a
+ * callback request is initiated.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise after 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
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
+ * is true, it will invoke the page's {@link TPage::validate validate}
+ * method first. It will raise {@link onClick OnClick} event first
+ * and then the {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->raisePostBackEvent($param);
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the button text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveButton';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveClientScript.php b/framework/Web/UI/ActiveControls/TActiveClientScript.php
index 423918d9..2e58b6b0 100755
--- a/framework/Web/UI/ActiveControls/TActiveClientScript.php
+++ b/framework/Web/UI/ActiveControls/TActiveClientScript.php
@@ -1,82 +1,82 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveClientScript class
- *
- * This is the active counterpart of the {@link TClientScript} class.
- *
- * TActiveClientScript has the ability to render itself on ajax
- * callbacks. This means that every variable or function declared in javascript
- * code will be available to the page.
- *
- * Beware that when rendered on normal (postback) or ajax callbacks, some
- * javascript code won't behave in the same way.
- * When rendered as part of a normal/postback response, scripts will execute instantly
- * where they are in the page and in a synchronous fashion.
- * Instead, when they are rendered as part of a callback response,
- * they will be executed when all DOM modifications are complete and any dynamic
- * script file includes are loaded, out-of-band and practically all blocks at once,
- * regardless of where they actually occour in the original template/markup code.
- * This can potentially hurt compatibility and graceful fallback.
- *
- * @author Wei Zhuo
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- * @since 3.2
- */
-
-class TActiveClientScript extends TClientScript
-{
- /**
- * Renders the custom script file.
- * @param THtmLWriter the renderer
- */
- protected function renderCustomScriptFile($writer)
- {
- if(($scriptUrl = $this->getScriptUrl())!=='')
- {
- if($this->getPage()->getIsCallback())
- {
- $cs = $this->getPage()->getClientScript();
- $uniqueid=$this->ClientID.'_custom';
- if(!$cs->isScriptFileRegistered($uniqueid))
- $cs->registerScriptFile($uniqueid, $scriptUrl);
- } else {
- $writer->write("\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("/*renderChildren($extWriter);
- $extWriter->write("\n/*]]>*/");
- $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
- } else {
- $writer->write("\n");
- }
- }
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveClientScript class
+ *
+ * This is the active counterpart of the {@link TClientScript} class.
+ *
+ * TActiveClientScript has the ability to render itself on ajax
+ * callbacks. This means that every variable or function declared in javascript
+ * code will be available to the page.
+ *
+ * Beware that when rendered on normal (postback) or ajax callbacks, some
+ * javascript code won't behave in the same way.
+ * When rendered as part of a normal/postback response, scripts will execute instantly
+ * where they are in the page and in a synchronous fashion.
+ * Instead, when they are rendered as part of a callback response,
+ * they will be executed when all DOM modifications are complete and any dynamic
+ * script file includes are loaded, out-of-band and practically all blocks at once,
+ * regardless of where they actually occour in the original template/markup code.
+ * This can potentially hurt compatibility and graceful fallback.
+ *
+ * @author Wei Zhuo
+ * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2
+ */
+
+class TActiveClientScript extends TClientScript
+{
+ /**
+ * Renders the custom script file.
+ * @param THtmLWriter the renderer
+ */
+ protected function renderCustomScriptFile($writer)
+ {
+ if(($scriptUrl = $this->getScriptUrl())!=='')
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $uniqueid=$this->ClientID.'_custom';
+ if(!$cs->isScriptFileRegistered($uniqueid))
+ $cs->registerScriptFile($uniqueid, $scriptUrl);
+ } else {
+ $writer->write("\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("/*renderChildren($extWriter);
+ $extWriter->write("\n/*]]>*/");
+ $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
+ } else {
+ $writer->write("\n");
+ }
+ }
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
index 8a0c8aec..7e7a82fe 100644
--- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
@@ -1,575 +1,575 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/*
- * Load common active control options.
- */
-Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
-
-/**
- * TActiveControlAdapter class.
- *
- * Customize the parent TControl class for active control classes.
- * TActiveControlAdapter instantiates a common base active control class
- * throught the {@link getBaseActiveControl BaseActiveControl} property.
- * The type of BaseActiveControl can be provided in the second parameter in the
- * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
- * the control adapted implements ICallbackEventHandler.
- *
- * TActiveControlAdapter will tracking viewstate changes to update the
- * corresponding client-side properties.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveControlAdapter extends TControlAdapter
-{
- /**
- * @var string base active control class name.
- */
- private $_activeControlType;
- /**
- * @var TBaseActiveControl base active control instance.
- */
- private $_baseActiveControl;
- /**
- * @var TCallbackPageStateTracker view state tracker.
- */
- private $_stateTracker;
-
- /**
- * Constructor.
- * @param IActiveControl active control to adapt.
- * @param string Base active control class name.
- */
- public function __construct(IActiveControl $control, $baseCallbackClass=null)
- {
- parent::__construct($control);
- $this->setBaseControlClass($baseCallbackClass);
- }
-
- /**
- * @param string base active control instance
- */
- protected function setBaseControlClass($type)
- {
- if($type===null)
- {
- if($this->getControl() instanceof ICallbackEventHandler)
- $this->_activeControlType = 'TBaseActiveCallbackControl';
- else
- $this->_activeControlType = 'TBaseActiveControl';
- }
- else
- $this->_activeControlType = $type;
- }
-
- /**
- * Publish the ajax script
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- }
-
- /**
- * Renders the callback client scripts.
- */
- public function render($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('ajax');
- $this->renderCallbackClientScripts();
- if($this->_control->getVisible(false))
- {
- parent::render($writer);
- } else {
- $writer->write("_control->getClientID()."\" style=\"display:none\"> ");
- }
- }
-
- /**
- * Register the callback clientscripts and sets the post loader IDs.
- */
- protected function renderCallbackClientScripts()
- {
- $cs = $this->getPage()->getClientScript();
- $key = 'Prado.CallbackRequest.addPostLoaders';
- if(!$cs->isEndScriptRegistered($key))
- {
- $data = $this->getPage()->getPostDataLoaders();
- if(count($data) > 0)
- {
- $options = TJavaScript::encode($data,false);
- $script = "Prado.CallbackRequest.addPostLoaders({$options});";
- $cs->registerEndScript($key, $script);
- }
- }
- }
-
- /**
- * @param TBaseActiveControl change base active control
- */
- public function setBaseActiveControl($control)
- {
- $this->_baseActiveControl=$control;
- }
-
- /**
- * @return TBaseActiveControl Common active control options.
- */
- public function getBaseActiveControl()
- {
- if($this->_baseActiveControl===null)
- {
- $type = $this->_activeControlType;
- $this->_baseActiveControl = new $type($this->getControl());
- }
- return $this->_baseActiveControl;
- }
-
- /**
- * @return boolean true if the viewstate needs to be tracked.
- */
- protected function getIsTrackingPageState()
- {
- if($this->getPage()->getIsCallback())
- {
- $target = $this->getPage()->getCallbackEventTarget();
- if($target instanceof ICallbackEventHandler)
- {
- $client = $target->getActiveControl()->getClientSide();
- return $client->getEnablePageStateUpdate();
- }
- }
- return false;
- }
-
- /**
- * Starts viewstate tracking if necessary after when controls has been loaded
- */
- public function onLoad($param)
- {
- if($this->getIsTrackingPageState())
- {
- $this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
- $this->_stateTracker->trackChanges();
- }
- parent::onLoad($param);
- }
-
- /**
- * Saves additional persistent control state. Respond to viewstate changes
- * if necessary.
- */
- public function saveState()
- {
- if(($this->_stateTracker!==null)
- && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
- {
- $this->_stateTracker->respondToChanges();
- }
- parent::saveState();
- }
-
- /**
- * @return TCallbackPageStateTracker state tracker.
- */
- public function getStateTracker()
- {
- return $this->_stateTracker;
- }
-}
-
-/**
- * TCallbackPageStateTracker class.
- *
- * Tracking changes to the page state during callback.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackPageStateTracker
-{
- /**
- * @var TMap new view state data
- */
- private $_states;
- /**
- * @var TMap old view state data
- */
- private $_existingState;
- /**
- * @var TControl the control tracked
- */
- private $_control;
- /**
- * @var object null object.
- */
- private $_nullObject;
-
- /**
- * Constructor. Add a set of default states to track.
- * @param TControl control to track.
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_existingState = new TMap;
- $this->_nullObject = new stdClass;
- $this->_states = new TMap;
- $this->addStatesToTrack();
- }
-
- /**
- * Add a list of view states to track. Each state is added
- * to the StatesToTrack property with the view state name as key.
- * The value should be an array with two enteries. The first entery
- * is the name of the class that will calculate the state differences.
- * The second entry is a php function/method callback that handles
- * the changes in the viewstate.
- */
- protected function addStatesToTrack()
- {
- $states = $this->getStatesToTrack();
- $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
- $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
- $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
- $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
- $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
- $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
- $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
- }
-
- /**
- * @return TMap list of viewstates to track.
- */
- protected function getStatesToTrack()
- {
- return $this->_states;
- }
-
- /**
- * Start tracking view state changes. The clone function on objects are called
- * for those viewstate having an object as value.
- */
- public function trackChanges()
- {
- foreach($this->_states as $name => $value)
- {
- $obj = $this->_control->getViewState($name);
- $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
- }
- }
-
- /**
- * @return array list of viewstate and the changed data.
- */
- protected function getChanges()
- {
- $changes = array();
- foreach($this->_states as $name => $details)
- {
- $new = $this->_control->getViewState($name);
- $old = $this->_existingState[$name];
- if($new !== $old)
- {
- $diff = new $details[0]($new, $old, $this->_nullObject);
- if(($change = $diff->getDifference()) !== $this->_nullObject)
- $changes[] = array($details[1],array($change));
- }
- }
- return $changes;
- }
-
- /**
- * For each of the changes call the corresponding change handlers.
- */
- public function respondToChanges()
- {
- foreach($this->getChanges() as $change)
- call_user_func_array($change[0], $change[1]);
- }
-
- /**
- * @return TCallbackClientScript callback client scripting
- */
- protected function client()
- {
- return $this->_control->getPage()->getCallbackClient();
- }
-
- /**
- * Updates the tooltip.
- * @param string new tooltip
- */
- protected function updateToolTip($value)
- {
- $this->client()->setAttribute($this->_control, 'title', $value);
- }
-
- /**
- * Updates the tab index.
- * @param integer tab index
- */
- protected function updateTabIndex($value)
- {
- $this->client()->setAttribute($this->_control, 'tabindex', $value);
- }
-
- /**
- * Updates the modifier access key
- * @param string access key
- */
- protected function updateAccessKey($value)
- {
- $this->client()->setAttribute($this->_control, 'accesskey', $value);
- }
-
- /**
- * Hides or shows the control on the client-side. The control must be
- * already rendered on the client-side.
- * @param boolean true to show the control, false to hide.
- */
- protected function updateVisible($visible)
- {
- if($visible === false)
- $this->client()->replaceContent($this->_control,"_control->getClientID()."\" style=\"display:none\" > ");
- 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
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TViewStateDiff
-{
- /**
- * @var mixed updated viewstate
- */
- protected $_new;
- /**
- * @var mixed viewstate value at the begining of the request.
- */
- protected $_old;
- /**
- * @var object null value.
- */
- protected $_null;
-
- /**
- * Constructor.
- * @param mixed updated viewstate value.
- * @param mixed viewstate value at the begining of the request.
- * @param object representing the null value.
- */
- public function __construct($new, $old, $null)
- {
- $this->_new = $new;
- $this->_old = $old;
- $this->_null = $null;
- }
-
- /**
- * @return mixed view state changes, nullObject if no difference.
- */
- public abstract function getDifference();
-}
-
-/**
- * TScalarDiff class.
- *
- * Calculate the changes to a scalar value.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TScalarDiff extends TViewStateDiff
-{
- /**
- * @return mixed update viewstate value.
- */
- public function getDifference()
- {
- if(gettype($this->_new) === gettype($this->_old)
- && $this->_new === $this->_old)
- return $this->_null;
- else
- return $this->_new;
- }
-}
-
-/**
- * TStyleDiff class.
- *
- * Calculates the changes to the Style properties.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TStyleDiff extends TViewStateDiff
-{
- /**
- * @param TStyle control style
- * @return array all the style properties combined.
- */
- protected function getCombinedStyle($obj)
- {
- if(!($obj instanceof TStyle))
- return array();
- $style = $obj->getStyleFields();
- $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
- if($obj->hasFont())
- $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
- return $style;
- }
-
- /**
- * @param string CSS custom style string.
- * @param array CSS style as name-value array.
- */
- protected function getStyleFromString($string)
- {
- $style = array();
- if(!is_string($string)) return $style;
-
- foreach(explode(';',$string) as $sub)
- {
- $arr=explode(':',$sub);
- if(isset($arr[1]) && trim($arr[0])!=='')
- $style[trim($arr[0])] = trim($arr[1]);
- }
- return $style;
- }
-
- /**
- * @return string changes to the CSS class name.
- */
- protected function getCssClassDiff()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) && $this->_new->hasCssClass()
- ? $this->_new->getCssClass() : null;
- }
- else
- {
- return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
- $this->_new->getCssClass() : null;
- }
- }
-
- /**
- * @return array list of changes to the control style.
- */
- protected function getStyleDiff()
- {
- $diff = array_diff_assoc(
- $this->getCombinedStyle($this->_new),
- $this->getCombinedStyle($this->_old));
- return count($diff) > 0 ? $diff : null;
- }
-
- /**
- * @return array list of changes to the control style and CSS class name.
- */
- public function getDifference()
- {
- if($this->_new===null)
- return $this->_null;
- else
- {
- $css = $this->getCssClassDiff();
- $style = $this->getStyleDiff();
- if(($css!==null) || ($style!==null))
- return array('CssClass' => $css, 'Style' => $style);
- else
- $this->_null;
- }
- }
-}
-
-/**
- * TAttributesDiff class.
- *
- * Calculate the changes to attributes collection.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TMapCollectionDiff extends TViewStateDiff
-{
- /**
- * @return array updates to the attributes collection.
- */
- public function getDifference()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
- }
- else
- {
- $new = $this->_new->toArray();
- $old = $this->_old->toArray();
- $diff = array_diff_assoc($new, $old);
- return count($diff) > 0 ? $diff : $this->_null;
- }
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/*
+ * Load common active control options.
+ */
+Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
+
+/**
+ * TActiveControlAdapter class.
+ *
+ * Customize the parent TControl class for active control classes.
+ * TActiveControlAdapter instantiates a common base active control class
+ * throught the {@link getBaseActiveControl BaseActiveControl} property.
+ * The type of BaseActiveControl can be provided in the second parameter in the
+ * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
+ * the control adapted implements ICallbackEventHandler.
+ *
+ * TActiveControlAdapter will tracking viewstate changes to update the
+ * corresponding client-side properties.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveControlAdapter extends TControlAdapter
+{
+ /**
+ * @var string base active control class name.
+ */
+ private $_activeControlType;
+ /**
+ * @var TBaseActiveControl base active control instance.
+ */
+ private $_baseActiveControl;
+ /**
+ * @var TCallbackPageStateTracker view state tracker.
+ */
+ private $_stateTracker;
+
+ /**
+ * Constructor.
+ * @param IActiveControl active control to adapt.
+ * @param string Base active control class name.
+ */
+ public function __construct(IActiveControl $control, $baseCallbackClass=null)
+ {
+ parent::__construct($control);
+ $this->setBaseControlClass($baseCallbackClass);
+ }
+
+ /**
+ * @param string base active control instance
+ */
+ protected function setBaseControlClass($type)
+ {
+ if($type===null)
+ {
+ if($this->getControl() instanceof ICallbackEventHandler)
+ $this->_activeControlType = 'TBaseActiveCallbackControl';
+ else
+ $this->_activeControlType = 'TBaseActiveControl';
+ }
+ else
+ $this->_activeControlType = $type;
+ }
+
+ /**
+ * Publish the ajax script
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Renders the callback client scripts.
+ */
+ public function render($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('ajax');
+ $this->renderCallbackClientScripts();
+ if($this->_control->getVisible(false))
+ {
+ parent::render($writer);
+ } else {
+ $writer->write("_control->getClientID()."\" style=\"display:none\"> ");
+ }
+ }
+
+ /**
+ * Register the callback clientscripts and sets the post loader IDs.
+ */
+ protected function renderCallbackClientScripts()
+ {
+ $cs = $this->getPage()->getClientScript();
+ $key = 'Prado.CallbackRequest.addPostLoaders';
+ if(!$cs->isEndScriptRegistered($key))
+ {
+ $data = $this->getPage()->getPostDataLoaders();
+ if(count($data) > 0)
+ {
+ $options = TJavaScript::encode($data,false);
+ $script = "Prado.CallbackRequest.addPostLoaders({$options});";
+ $cs->registerEndScript($key, $script);
+ }
+ }
+ }
+
+ /**
+ * @param TBaseActiveControl change base active control
+ */
+ public function setBaseActiveControl($control)
+ {
+ $this->_baseActiveControl=$control;
+ }
+
+ /**
+ * @return TBaseActiveControl Common active control options.
+ */
+ public function getBaseActiveControl()
+ {
+ if($this->_baseActiveControl===null)
+ {
+ $type = $this->_activeControlType;
+ $this->_baseActiveControl = new $type($this->getControl());
+ }
+ return $this->_baseActiveControl;
+ }
+
+ /**
+ * @return boolean true if the viewstate needs to be tracked.
+ */
+ protected function getIsTrackingPageState()
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $target = $this->getPage()->getCallbackEventTarget();
+ if($target instanceof ICallbackEventHandler)
+ {
+ $client = $target->getActiveControl()->getClientSide();
+ return $client->getEnablePageStateUpdate();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Starts viewstate tracking if necessary after when controls has been loaded
+ */
+ public function onLoad($param)
+ {
+ if($this->getIsTrackingPageState())
+ {
+ $this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
+ $this->_stateTracker->trackChanges();
+ }
+ parent::onLoad($param);
+ }
+
+ /**
+ * Saves additional persistent control state. Respond to viewstate changes
+ * if necessary.
+ */
+ public function saveState()
+ {
+ if(($this->_stateTracker!==null)
+ && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
+ {
+ $this->_stateTracker->respondToChanges();
+ }
+ parent::saveState();
+ }
+
+ /**
+ * @return TCallbackPageStateTracker state tracker.
+ */
+ public function getStateTracker()
+ {
+ return $this->_stateTracker;
+ }
+}
+
+/**
+ * TCallbackPageStateTracker class.
+ *
+ * Tracking changes to the page state during callback.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackPageStateTracker
+{
+ /**
+ * @var TMap new view state data
+ */
+ private $_states;
+ /**
+ * @var TMap old view state data
+ */
+ private $_existingState;
+ /**
+ * @var TControl the control tracked
+ */
+ private $_control;
+ /**
+ * @var object null object.
+ */
+ private $_nullObject;
+
+ /**
+ * Constructor. Add a set of default states to track.
+ * @param TControl control to track.
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_existingState = new TMap;
+ $this->_nullObject = new stdClass;
+ $this->_states = new TMap;
+ $this->addStatesToTrack();
+ }
+
+ /**
+ * Add a list of view states to track. Each state is added
+ * to the StatesToTrack property with the view state name as key.
+ * The value should be an array with two enteries. The first entery
+ * is the name of the class that will calculate the state differences.
+ * The second entry is a php function/method callback that handles
+ * the changes in the viewstate.
+ */
+ protected function addStatesToTrack()
+ {
+ $states = $this->getStatesToTrack();
+ $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
+ $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
+ $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
+ $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
+ $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
+ $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
+ $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
+ }
+
+ /**
+ * @return TMap list of viewstates to track.
+ */
+ protected function getStatesToTrack()
+ {
+ return $this->_states;
+ }
+
+ /**
+ * Start tracking view state changes. The clone function on objects are called
+ * for those viewstate having an object as value.
+ */
+ public function trackChanges()
+ {
+ foreach($this->_states as $name => $value)
+ {
+ $obj = $this->_control->getViewState($name);
+ $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
+ }
+ }
+
+ /**
+ * @return array list of viewstate and the changed data.
+ */
+ protected function getChanges()
+ {
+ $changes = array();
+ foreach($this->_states as $name => $details)
+ {
+ $new = $this->_control->getViewState($name);
+ $old = $this->_existingState[$name];
+ if($new !== $old)
+ {
+ $diff = new $details[0]($new, $old, $this->_nullObject);
+ if(($change = $diff->getDifference()) !== $this->_nullObject)
+ $changes[] = array($details[1],array($change));
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * For each of the changes call the corresponding change handlers.
+ */
+ public function respondToChanges()
+ {
+ foreach($this->getChanges() as $change)
+ call_user_func_array($change[0], $change[1]);
+ }
+
+ /**
+ * @return TCallbackClientScript callback client scripting
+ */
+ protected function client()
+ {
+ return $this->_control->getPage()->getCallbackClient();
+ }
+
+ /**
+ * Updates the tooltip.
+ * @param string new tooltip
+ */
+ protected function updateToolTip($value)
+ {
+ $this->client()->setAttribute($this->_control, 'title', $value);
+ }
+
+ /**
+ * Updates the tab index.
+ * @param integer tab index
+ */
+ protected function updateTabIndex($value)
+ {
+ $this->client()->setAttribute($this->_control, 'tabindex', $value);
+ }
+
+ /**
+ * Updates the modifier access key
+ * @param string access key
+ */
+ protected function updateAccessKey($value)
+ {
+ $this->client()->setAttribute($this->_control, 'accesskey', $value);
+ }
+
+ /**
+ * Hides or shows the control on the client-side. The control must be
+ * already rendered on the client-side.
+ * @param boolean true to show the control, false to hide.
+ */
+ protected function updateVisible($visible)
+ {
+ if($visible === false)
+ $this->client()->replaceContent($this->_control,"_control->getClientID()."\" style=\"display:none\" > ");
+ 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
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TViewStateDiff
+{
+ /**
+ * @var mixed updated viewstate
+ */
+ protected $_new;
+ /**
+ * @var mixed viewstate value at the begining of the request.
+ */
+ protected $_old;
+ /**
+ * @var object null value.
+ */
+ protected $_null;
+
+ /**
+ * Constructor.
+ * @param mixed updated viewstate value.
+ * @param mixed viewstate value at the begining of the request.
+ * @param object representing the null value.
+ */
+ public function __construct($new, $old, $null)
+ {
+ $this->_new = $new;
+ $this->_old = $old;
+ $this->_null = $null;
+ }
+
+ /**
+ * @return mixed view state changes, nullObject if no difference.
+ */
+ public abstract function getDifference();
+}
+
+/**
+ * TScalarDiff class.
+ *
+ * Calculate the changes to a scalar value.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TScalarDiff extends TViewStateDiff
+{
+ /**
+ * @return mixed update viewstate value.
+ */
+ public function getDifference()
+ {
+ if(gettype($this->_new) === gettype($this->_old)
+ && $this->_new === $this->_old)
+ return $this->_null;
+ else
+ return $this->_new;
+ }
+}
+
+/**
+ * TStyleDiff class.
+ *
+ * Calculates the changes to the Style properties.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TStyleDiff extends TViewStateDiff
+{
+ /**
+ * @param TStyle control style
+ * @return array all the style properties combined.
+ */
+ protected function getCombinedStyle($obj)
+ {
+ if(!($obj instanceof TStyle))
+ return array();
+ $style = $obj->getStyleFields();
+ $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
+ if($obj->hasFont())
+ $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
+ return $style;
+ }
+
+ /**
+ * @param string CSS custom style string.
+ * @param array CSS style as name-value array.
+ */
+ protected function getStyleFromString($string)
+ {
+ $style = array();
+ if(!is_string($string)) return $style;
+
+ foreach(explode(';',$string) as $sub)
+ {
+ $arr=explode(':',$sub);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $style[trim($arr[0])] = trim($arr[1]);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string changes to the CSS class name.
+ */
+ protected function getCssClassDiff()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) && $this->_new->hasCssClass()
+ ? $this->_new->getCssClass() : null;
+ }
+ else
+ {
+ return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
+ $this->_new->getCssClass() : null;
+ }
+ }
+
+ /**
+ * @return array list of changes to the control style.
+ */
+ protected function getStyleDiff()
+ {
+ $diff = array_diff_assoc(
+ $this->getCombinedStyle($this->_new),
+ $this->getCombinedStyle($this->_old));
+ return count($diff) > 0 ? $diff : null;
+ }
+
+ /**
+ * @return array list of changes to the control style and CSS class name.
+ */
+ public function getDifference()
+ {
+ if($this->_new===null)
+ return $this->_null;
+ else
+ {
+ $css = $this->getCssClassDiff();
+ $style = $this->getStyleDiff();
+ if(($css!==null) || ($style!==null))
+ return array('CssClass' => $css, 'Style' => $style);
+ else
+ $this->_null;
+ }
+ }
+}
+
+/**
+ * TAttributesDiff class.
+ *
+ * Calculate the changes to attributes collection.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TMapCollectionDiff extends TViewStateDiff
+{
+ /**
+ * @return array updates to the attributes collection.
+ */
+ public function getDifference()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
+ }
+ else
+ {
+ $new = $this->_new->toArray();
+ $old = $this->_old->toArray();
+ $diff = array_diff_assoc($new, $old);
+ return count($diff) > 0 ? $diff : $this->_null;
+ }
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
index 9e09eb88..df8f45d9 100644
--- a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
+++ b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
@@ -1,265 +1,265 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TActiveCustomValidator Class
- *
- * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
- * validation event. The client-side uses callbacks to raise
- * the {@link onServerValidate onServerValidate} event.
- *
- * Beware that the {@link onServerValidate onServerValidate} may be
- * raised when the control to validate on the client side
- * changes value, that is, the server validation may be called many times.
- *
- * After the callback or postback, the {@link onServerValidate onServerValidate}
- * is raised once more. The {@link getIsCallback IsCallback} property
- * will be true when validation is made during a callback request.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidator extends TCustomValidator
- implements ICallbackEventHandler, IActiveControl
-{
- /**
- * @var boolean true if validation is made during a callback request.
- */
- private $_isCallback = false;
-
- /**
- * @return boolean true if validation is made during a callback request.
- */
- public function getIsCallback()
- {
- return $this->_isCallback;
- }
-
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client validation function is NOT supported.
- */
- public function setClientValidationFunction($value)
- {
- throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
- get_class($this));
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface. The {@link onServerValidate
- * OnServerValidate} event is raised first and then the
- * {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->_isCallback = true;
- $result = $this->onServerValidate($param->getCallbackParameter());
- $param->setResponseData($result);
- $this->onCallback($param);
- }
-
- /**
- * @param boolean whether the value is valid; this method will trigger a clientside update if needed
- */
- public function setIsValid($value)
- {
- parent::setIsValid($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.updateActiveCustomValidator';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=TBaseValidator::getClientScriptOptions();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-
- /**
- * Sets the text for the error message. Updates client-side erorr message.
- * @param string the error message
- */
- public function setErrorMessage($value)
- {
- parent::setErrorMessage($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.setErrorMessage';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
-
- /**
- * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
- * @return boolean whether client-side validation is enabled.
- */
- public function getEnableClientScript()
- {
- return true;
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- TBaseValidator::registerClientScriptValidator();
- }
-
- /**
- * @return string corresponding javascript class name for this this.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveCustomValidator';
- }
-}
-
-/**
- * Custom Validator callback client side options class.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidatorClientSide extends TCallbackClientSide
-{
- /**
- * @return string javascript code for client-side OnValidate event.
- */
- public function getOnValidate()
- {
- return $this->getOption('OnValidate');
- }
-
- /**
- * Client-side OnValidate validator event is raise before the validators
- * validation functions are called.
- * @param string javascript code for client-side OnValidate event.
- */
- public function setOnValidate($javascript)
- {
- $this->setFunction('OnValidate', $javascript);
- }
-
- /**
- * Client-side OnSuccess event is raise after validation is successfull.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnSuccess event.
- */
- public function setOnValidationSuccess($javascript)
- {
- $this->setFunction('OnValidationSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnSuccess event.
- */
- public function getOnValidationSuccess()
- {
- return $this->getOption('OnValidationSuccess');
- }
-
- /**
- * Client-side OnError event is raised after validation failure.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnError event.
- */
- public function setOnValidationError($javascript)
- {
- $this->setFunction('OnValidationError', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnError event.
- */
- public function getOnValidationError()
- {
- return $this->getOption('OnValidationError');
- }
-
- /**
- * @param boolean true to revalidate when the control to validate changes value.
- */
- public function setObserveChanges($value)
- {
- $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return boolean true to observe changes.
- */
- public function getObserveChanges()
- {
- $changes = $this->getOption('ObserveChanges');
- return ($changes===null) ? true : $changes;
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TActiveCustomValidator Class
+ *
+ * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
+ * validation event. The client-side uses callbacks to raise
+ * the {@link onServerValidate onServerValidate} event.
+ *
+ * Beware that the {@link onServerValidate onServerValidate} may be
+ * raised when the control to validate on the client side
+ * changes value, that is, the server validation may be called many times.
+ *
+ * After the callback or postback, the {@link onServerValidate onServerValidate}
+ * is raised once more. The {@link getIsCallback IsCallback} property
+ * will be true when validation is made during a callback request.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidator extends TCustomValidator
+ implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * @var boolean true if validation is made during a callback request.
+ */
+ private $_isCallback = false;
+
+ /**
+ * @return boolean true if validation is made during a callback request.
+ */
+ public function getIsCallback()
+ {
+ return $this->_isCallback;
+ }
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client validation function is NOT supported.
+ */
+ public function setClientValidationFunction($value)
+ {
+ throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface. The {@link onServerValidate
+ * OnServerValidate} event is raised first and then the
+ * {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->_isCallback = true;
+ $result = $this->onServerValidate($param->getCallbackParameter());
+ $param->setResponseData($result);
+ $this->onCallback($param);
+ }
+
+ /**
+ * @param boolean whether the value is valid; this method will trigger a clientside update if needed
+ */
+ public function setIsValid($value)
+ {
+ parent::setIsValid($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.updateActiveCustomValidator';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=TBaseValidator::getClientScriptOptions();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Sets the text for the error message. Updates client-side erorr message.
+ * @param string the error message
+ */
+ public function setErrorMessage($value)
+ {
+ parent::setErrorMessage($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.setErrorMessage';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+
+ /**
+ * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
+ * @return boolean whether client-side validation is enabled.
+ */
+ public function getEnableClientScript()
+ {
+ return true;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ TBaseValidator::registerClientScriptValidator();
+ }
+
+ /**
+ * @return string corresponding javascript class name for this this.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveCustomValidator';
+ }
+}
+
+/**
+ * Custom Validator callback client side options class.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidatorClientSide extends TCallbackClientSide
+{
+ /**
+ * @return string javascript code for client-side OnValidate event.
+ */
+ public function getOnValidate()
+ {
+ return $this->getOption('OnValidate');
+ }
+
+ /**
+ * Client-side OnValidate validator event is raise before the validators
+ * validation functions are called.
+ * @param string javascript code for client-side OnValidate event.
+ */
+ public function setOnValidate($javascript)
+ {
+ $this->setFunction('OnValidate', $javascript);
+ }
+
+ /**
+ * Client-side OnSuccess event is raise after validation is successfull.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnSuccess event.
+ */
+ public function setOnValidationSuccess($javascript)
+ {
+ $this->setFunction('OnValidationSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnSuccess event.
+ */
+ public function getOnValidationSuccess()
+ {
+ return $this->getOption('OnValidationSuccess');
+ }
+
+ /**
+ * Client-side OnError event is raised after validation failure.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnError event.
+ */
+ public function setOnValidationError($javascript)
+ {
+ $this->setFunction('OnValidationError', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnError event.
+ */
+ public function getOnValidationError()
+ {
+ return $this->getOption('OnValidationError');
+ }
+
+ /**
+ * @param boolean true to revalidate when the control to validate changes value.
+ */
+ public function setObserveChanges($value)
+ {
+ $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return boolean true to observe changes.
+ */
+ public function getObserveChanges()
+ {
+ $changes = $this->getOption('ObserveChanges');
+ return ($changes===null) ? true : $changes;
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php
index 32d91cd2..c05b1744 100644
--- a/framework/Web/UI/ActiveControls/TActiveLabel.php
+++ b/framework/Web/UI/ActiveControls/TActiveLabel.php
@@ -80,7 +80,7 @@ class TActiveLabel extends TLabel implements IActiveControl
/**
* Adds attribute id to the renderer.
- * @param THtmlWriter the writer used for the rendering purpose
+ * @param THtmlWriter the writer used for the rendering purpose
*/
protected function addAttributesToRender($writer) {
$writer->addAttribute('id',$this->getClientID());
diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php
index 726dd8ba..144f621e 100644
--- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php
@@ -1,401 +1,401 @@
-
- * @author Gabor Berczi (lazyload additions & progressive rendering)
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load callback response adapter class.
- */
-Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TActivePageAdapter class.
- *
- * Callback request handler.
- *
- * @author Wei Zhuo
- * @author Gabor Berczi (lazyload additions & progressive rendering)
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePageAdapter extends TControlAdapter
-{
- /**
- * Callback response data header name.
- */
- const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
- /**
- * Callback response client-side action header name.
- */
- const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
- /**
- * Callback error header name.
- */
- const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
- /**
- * Callback page state header name.
- */
- const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
- /**
- * Script list header name.
- */
- const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
- /**
- * Stylesheet list header name.
- */
- const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
- /**
- * Hidden field list header name.
- */
- const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
-
- /**
- * Callback redirect url header name.
- */
- const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
-
- /**
- * @var ICallbackEventHandler callback event handler.
- */
- private $_callbackEventTarget;
- /**
- * @var mixed callback event parameter.
- */
- private $_callbackEventParameter;
- /**
- * @var TCallbackClientScript callback client script handler
- */
- private $_callbackClient;
-
- private $_controlsToRender=array();
-
- /**
- * Constructor, trap errors and exception to let the callback response
- * handle them.
- */
- public function __construct(TPage $control)
- {
- parent::__construct($control);
-
- //TODO: can this be done later?
- $response = $this->getApplication()->getResponse();
- $response->setAdapter(new TCallbackResponseAdapter($response));
-
- $this->trapCallbackErrorsExceptions();
- }
-
- /**
- * Process the callback request.
- * @param THtmlWriter html content writer.
- */
- public function processCallbackEvent($writer)
- {
- Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->raiseCallbackEvent();
- }
-
- /**
- * Register a control for defered render() call.
- * @param TControl control for defered rendering
- * @param THtmlWriter the renderer
- */
- public function registerControlToRender($control,$writer)
- {
- $id = $control->getUniqueID();
- if(!isset($this->_controlsToRender[$id]))
- $this->_controlsToRender[$id] = array($control,$writer);
- }
-
- /**
- * Trap errors and exceptions to be handled by TCallbackErrorHandler.
- */
- protected function trapCallbackErrorsExceptions()
- {
- $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
- }
-
- /**
- * Render the callback response.
- * @param THtmlWriter html content writer.
- */
- public function renderCallbackResponse($writer)
- {
- Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
- $this->renderResponse($writer);
- else
- $this->redirect($url);
- }
-
- /**
- * Redirect url on the client-side using javascript.
- * @param string new url to load.
- */
- protected function redirect($url)
- {
- Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
- //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url);
- }
-
- /**
- * Renders the callback response by adding additional callback data and
- * javascript actions in the header and page state if required.
- * @param THtmlWriter html content writer.
- */
- protected function renderResponse($writer)
- {
- Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- //renders all the defered render() calls.
- foreach($this->_controlsToRender as $rid => $forRender)
- $forRender[0]->render($forRender[1]);
-
- $response = $this->getResponse();
-
- //send response data in header
- if($response->getHasAdapter())
- {
- $responseData = $response->getAdapter()->getResponseData();
- if($responseData!==null)
- {
- $data = TJavaScript::jsonEncode($responseData);
-
- $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
- //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data);
- }
- }
-
- //sends page state in header
- if(($handler = $this->getCallbackEventTarget()) !== null)
- {
- if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
- {
- $pagestate = $this->getPage()->getClientState();
- $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
- //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate);
- }
- }
-
- //safari must receive at least 1 byte of data.
- $writer->write(" ");
-
- //output the end javascript
- if($this->getPage()->getClientScript()->hasEndScripts())
- {
- $writer = $response->createHtmlWriter();
- $this->getPage()->getClientScript()->renderEndScripts($writer);
- $this->getPage()->getCallbackClient()->evaluateScript($writer);
- }
-
- //output the actions
- $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
- $actions = TJavaScript::jsonEncode($executeJavascript);
- $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
- //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions);
-
-
- $cs = $this->Page->getClientScript();
-
- // collect all stylesheet file references
- $stylesheets = $cs->getStyleSheetUrls();
- if (count($stylesheets)>0)
- $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
-
- // collect all script file references
- $scripts = $cs->getScriptUrls();
- if (count($scripts)>0)
- $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
-
- // collect all hidden field references
- $fields = $cs->getHiddenFields();
- if (count($fields)>0)
- $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
- }
-
- /**
- * Appends data or javascript code to the body content surrounded with delimiters
- */
- private function appendContentPart($response, $delimiter, $data)
- {
- $content = $response->createHtmlWriter();
- $content->getWriter()->setBoundary($delimiter);
- $content->write($data);
- }
-
- /**
- * Trys to find the callback event handler and raise its callback event.
- * @throws TInvalidCallbackException if call back target is not found.
- * @throws TInvalidCallbackException if the requested target does not
- * implement ICallbackEventHandler.
- */
- private function raiseCallbackEvent()
- {
- if(($callbackHandler=$this->getCallbackEventTarget())!==null)
- {
- if($callbackHandler instanceof ICallbackEventHandler)
- {
- $param = $this->getCallbackEventParameter();
- $result = new TCallbackEventParameter($this->getResponse(), $param);
- $callbackHandler->raiseCallbackEvent($result);
- }
- else
- {
- throw new TInvalidCallbackException(
- 'callback_invalid_handler', $callbackHandler->getUniqueID());
- }
- }
- else
- {
- $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- throw new TInvalidCallbackException('callback_invalid_target', $target);
- }
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- if($this->_callbackEventTarget===null)
- {
- $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- if(!empty($eventTarget))
- $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
- }
- return $this->_callbackEventTarget;
- }
-
- /**
- * Registers a control to raise callback event in the current request.
- * @param TControl control registered to raise callback event.
- */
- public function setCallbackEventTarget(TControl $control)
- {
- $this->_callbackEventTarget=$control;
- }
-
- /**
- * Gets callback parameter. JSON encoding is assumed.
- * @return string postback event parameter
- */
- public function getCallbackEventParameter()
- {
- if($this->_callbackEventParameter===null)
- {
- $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
- if(strlen($param) > 0)
- $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param);
- }
- return $this->_callbackEventParameter;
- }
-
- /**
- * @param mixed postback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->_callbackEventParameter=$value;
- }
-
- /**
- * Gets the callback client script handler. It handlers the javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript callback client handler.
- */
- public function getCallbackClientHandler()
- {
- if($this->_callbackClient===null)
- $this->_callbackClient = new TCallbackClientScript;
- return $this->_callbackClient;
- }
-}
-
-/**
- * TCallbackErrorHandler class.
- *
- * Captures errors and exceptions and send them back during callback response.
- * When the application is in debug mode, the error and exception stack trace
- * are shown. A TJavascriptLogger must be present on the client-side to view
- * the error stack trace.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackErrorHandler extends TErrorHandler
-{
- /**
- * Displays the exceptions to the client-side TJavascriptLogger.
- * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
- * @param Exception exception details.
- */
- protected function displayException($exception)
- {
- if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
- {
- $response = $this->getApplication()->getResponse();
- $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception));
- $response->setStatusCode(500, 'Internal Server Error');
- $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace);
- }
- else
- {
- error_log("Error happened while processing an existing error:\n".$exception->__toString());
- header('HTTP/1.0 500 Internal Server Error', true, 500);
- }
- $this->getApplication()->getResponse()->flush();
- }
-
- /**
- * @param Exception exception details.
- * @return array exception stack trace details.
- */
- private function getExceptionStackTrace($exception)
- {
- $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
- $data['file']=$exception->getFile();
- $data['line']=$exception->getLine();
- $data['trace']=$exception->getTrace();
- if($exception instanceof TPhpErrorException)
- {
- // if PHP exception, we want to show the 2nd stack level context
- // because the 1st stack level is of little use (it's in error handler)
- if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
- {
- $data['file']=$trace[0]['file'];
- $data['line']=$trace[0]['line'];
- }
- }
- $data['type']=get_class($exception);
- $data['message']=$exception->getMessage();
- $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
- $data['time']=@strftime('%Y-%m-%d %H:%M',time());
- return $data;
- }
-}
-
-/**
- * TInvalidCallbackException class.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInvalidCallbackException extends TException
-{
-}
-
+
+ * @author Gabor Berczi (lazyload additions & progressive rendering)
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load callback response adapter class.
+ */
+Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TActivePageAdapter class.
+ *
+ * Callback request handler.
+ *
+ * @author Wei Zhuo
+ * @author Gabor Berczi (lazyload additions & progressive rendering)
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePageAdapter extends TControlAdapter
+{
+ /**
+ * Callback response data header name.
+ */
+ const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
+ /**
+ * Callback response client-side action header name.
+ */
+ const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
+ /**
+ * Callback error header name.
+ */
+ const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
+ /**
+ * Callback page state header name.
+ */
+ const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
+ /**
+ * Script list header name.
+ */
+ const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
+ /**
+ * Stylesheet list header name.
+ */
+ const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
+ /**
+ * Hidden field list header name.
+ */
+ const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
+
+ /**
+ * Callback redirect url header name.
+ */
+ const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
+
+ /**
+ * @var ICallbackEventHandler callback event handler.
+ */
+ private $_callbackEventTarget;
+ /**
+ * @var mixed callback event parameter.
+ */
+ private $_callbackEventParameter;
+ /**
+ * @var TCallbackClientScript callback client script handler
+ */
+ private $_callbackClient;
+
+ private $_controlsToRender=array();
+
+ /**
+ * Constructor, trap errors and exception to let the callback response
+ * handle them.
+ */
+ public function __construct(TPage $control)
+ {
+ parent::__construct($control);
+
+ //TODO: can this be done later?
+ $response = $this->getApplication()->getResponse();
+ $response->setAdapter(new TCallbackResponseAdapter($response));
+
+ $this->trapCallbackErrorsExceptions();
+ }
+
+ /**
+ * Process the callback request.
+ * @param THtmlWriter html content writer.
+ */
+ public function processCallbackEvent($writer)
+ {
+ Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->raiseCallbackEvent();
+ }
+
+ /**
+ * Register a control for defered render() call.
+ * @param TControl control for defered rendering
+ * @param THtmlWriter the renderer
+ */
+ public function registerControlToRender($control,$writer)
+ {
+ $id = $control->getUniqueID();
+ if(!isset($this->_controlsToRender[$id]))
+ $this->_controlsToRender[$id] = array($control,$writer);
+ }
+
+ /**
+ * Trap errors and exceptions to be handled by TCallbackErrorHandler.
+ */
+ protected function trapCallbackErrorsExceptions()
+ {
+ $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
+ }
+
+ /**
+ * Render the callback response.
+ * @param THtmlWriter html content writer.
+ */
+ public function renderCallbackResponse($writer)
+ {
+ Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
+ $this->renderResponse($writer);
+ else
+ $this->redirect($url);
+ }
+
+ /**
+ * Redirect url on the client-side using javascript.
+ * @param string new url to load.
+ */
+ protected function redirect($url)
+ {
+ Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
+ //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url);
+ }
+
+ /**
+ * Renders the callback response by adding additional callback data and
+ * javascript actions in the header and page state if required.
+ * @param THtmlWriter html content writer.
+ */
+ protected function renderResponse($writer)
+ {
+ Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ //renders all the defered render() calls.
+ foreach($this->_controlsToRender as $rid => $forRender)
+ $forRender[0]->render($forRender[1]);
+
+ $response = $this->getResponse();
+
+ //send response data in header
+ if($response->getHasAdapter())
+ {
+ $responseData = $response->getAdapter()->getResponseData();
+ if($responseData!==null)
+ {
+ $data = TJavaScript::jsonEncode($responseData);
+
+ $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
+ //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data);
+ }
+ }
+
+ //sends page state in header
+ if(($handler = $this->getCallbackEventTarget()) !== null)
+ {
+ if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
+ {
+ $pagestate = $this->getPage()->getClientState();
+ $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
+ //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate);
+ }
+ }
+
+ //safari must receive at least 1 byte of data.
+ $writer->write(" ");
+
+ //output the end javascript
+ if($this->getPage()->getClientScript()->hasEndScripts())
+ {
+ $writer = $response->createHtmlWriter();
+ $this->getPage()->getClientScript()->renderEndScripts($writer);
+ $this->getPage()->getCallbackClient()->evaluateScript($writer);
+ }
+
+ //output the actions
+ $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
+ $actions = TJavaScript::jsonEncode($executeJavascript);
+ $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
+ //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions);
+
+
+ $cs = $this->Page->getClientScript();
+
+ // collect all stylesheet file references
+ $stylesheets = $cs->getStyleSheetUrls();
+ if (count($stylesheets)>0)
+ $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
+
+ // collect all script file references
+ $scripts = $cs->getScriptUrls();
+ if (count($scripts)>0)
+ $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
+
+ // collect all hidden field references
+ $fields = $cs->getHiddenFields();
+ if (count($fields)>0)
+ $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
+ }
+
+ /**
+ * Appends data or javascript code to the body content surrounded with delimiters
+ */
+ private function appendContentPart($response, $delimiter, $data)
+ {
+ $content = $response->createHtmlWriter();
+ $content->getWriter()->setBoundary($delimiter);
+ $content->write($data);
+ }
+
+ /**
+ * Trys to find the callback event handler and raise its callback event.
+ * @throws TInvalidCallbackException if call back target is not found.
+ * @throws TInvalidCallbackException if the requested target does not
+ * implement ICallbackEventHandler.
+ */
+ private function raiseCallbackEvent()
+ {
+ if(($callbackHandler=$this->getCallbackEventTarget())!==null)
+ {
+ if($callbackHandler instanceof ICallbackEventHandler)
+ {
+ $param = $this->getCallbackEventParameter();
+ $result = new TCallbackEventParameter($this->getResponse(), $param);
+ $callbackHandler->raiseCallbackEvent($result);
+ }
+ else
+ {
+ throw new TInvalidCallbackException(
+ 'callback_invalid_handler', $callbackHandler->getUniqueID());
+ }
+ }
+ else
+ {
+ $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ throw new TInvalidCallbackException('callback_invalid_target', $target);
+ }
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ if($this->_callbackEventTarget===null)
+ {
+ $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
+ }
+ return $this->_callbackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->_callbackEventTarget=$control;
+ }
+
+ /**
+ * Gets callback parameter. JSON encoding is assumed.
+ * @return string postback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ if($this->_callbackEventParameter===null)
+ {
+ $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ if(strlen($param) > 0)
+ $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param);
+ }
+ return $this->_callbackEventParameter;
+ }
+
+ /**
+ * @param mixed postback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->_callbackEventParameter=$value;
+ }
+
+ /**
+ * Gets the callback client script handler. It handlers the javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript callback client handler.
+ */
+ public function getCallbackClientHandler()
+ {
+ if($this->_callbackClient===null)
+ $this->_callbackClient = new TCallbackClientScript;
+ return $this->_callbackClient;
+ }
+}
+
+/**
+ * TCallbackErrorHandler class.
+ *
+ * Captures errors and exceptions and send them back during callback response.
+ * When the application is in debug mode, the error and exception stack trace
+ * are shown. A TJavascriptLogger must be present on the client-side to view
+ * the error stack trace.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackErrorHandler extends TErrorHandler
+{
+ /**
+ * Displays the exceptions to the client-side TJavascriptLogger.
+ * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
+ * @param Exception exception details.
+ */
+ protected function displayException($exception)
+ {
+ if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
+ {
+ $response = $this->getApplication()->getResponse();
+ $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception));
+ $response->setStatusCode(500, 'Internal Server Error');
+ $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace);
+ }
+ else
+ {
+ error_log("Error happened while processing an existing error:\n".$exception->__toString());
+ header('HTTP/1.0 500 Internal Server Error', true, 500);
+ }
+ $this->getApplication()->getResponse()->flush();
+ }
+
+ /**
+ * @param Exception exception details.
+ * @return array exception stack trace details.
+ */
+ private function getExceptionStackTrace($exception)
+ {
+ $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
+ $data['file']=$exception->getFile();
+ $data['line']=$exception->getLine();
+ $data['trace']=$exception->getTrace();
+ if($exception instanceof TPhpErrorException)
+ {
+ // if PHP exception, we want to show the 2nd stack level context
+ // because the 1st stack level is of little use (it's in error handler)
+ if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
+ {
+ $data['file']=$trace[0]['file'];
+ $data['line']=$trace[0]['line'];
+ }
+ }
+ $data['type']=get_class($exception);
+ $data['message']=$exception->getMessage();
+ $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
+ $data['time']=@strftime('%Y-%m-%d %H:%M',time());
+ return $data;
+ }
+}
+
+/**
+ * TInvalidCallbackException class.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInvalidCallbackException extends TException
+{
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActivePanel.php b/framework/Web/UI/ActiveControls/TActivePanel.php
index ae1dd09f..1edfa57c 100644
--- a/framework/Web/UI/ActiveControls/TActivePanel.php
+++ b/framework/Web/UI/ActiveControls/TActivePanel.php
@@ -1,100 +1,100 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActivePanel is the TPanel active control counterpart.
- *
- * TActivePanel allows the client-side panel contents to be updated during a
- * callback response using the {@link render} method.
- *
- * Example: Assume $param is an instance of TCallbackEventParameter attached to
- * the OnCallback event of a TCallback with ID "callback1", and
- * "panel1" is the ID of a TActivePanel.
- *
- * function callback1_requested($sender, $param)
- * {
- * $this->panel1->render($param->getNewWriter());
- * }
- *
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePanel extends TPanel implements IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveControl standard active control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * Adds attribute id to the renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer) {
- $writer->addAttribute('id',$this->getClientID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders and replaces the panel's content on the client-side.
- * When render() is called before the OnPreRender event, such as when render()
- * is called during a callback event handler, the rendering
- * is defered until OnPreRender event is raised.
- * @param THtmlWriter html writer
- */
- public function render($writer)
- {
- if($this->getHasPreRendered())
- {
- parent::render($writer);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
- }
- else
- {
- $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
- if ($this->getHasControls())
- {
- // If we update a TActivePanel on callback,
- // We shouldn't update all childs, because the whole content will be replaced by
- // the parent
- foreach ($this->findControlsByType('IActiveControl', false) as $control)
- {
- $control->getActiveControl()->setEnableUpdate(false);
- }
- }
- }
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActivePanel is the TPanel active control counterpart.
+ *
+ * TActivePanel allows the client-side panel contents to be updated during a
+ * callback response using the {@link render} method.
+ *
+ * Example: Assume $param is an instance of TCallbackEventParameter attached to
+ * the OnCallback event of a TCallback with ID "callback1", and
+ * "panel1" is the ID of a TActivePanel.
+ *
+ * function callback1_requested($sender, $param)
+ * {
+ * $this->panel1->render($param->getNewWriter());
+ * }
+ *
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePanel extends TPanel implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Adds attribute id to the renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer) {
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders and replaces the panel's content on the client-side.
+ * When render() is called before the OnPreRender event, such as when render()
+ * is called during a callback event handler, the rendering
+ * is defered until OnPreRender event is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ if ($this->getHasControls())
+ {
+ // If we update a TActivePanel on callback,
+ // We shouldn't update all childs, because the whole content will be replaced by
+ // the parent
+ foreach ($this->findControlsByType('IActiveControl', false) as $control)
+ {
+ $control->getActiveControl()->setEnableUpdate(false);
+ }
+ }
+ }
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveRatingList.php b/framework/Web/UI/ActiveControls/TActiveRatingList.php
index 7c878dd8..81f50dd1 100644
--- a/framework/Web/UI/ActiveControls/TActiveRatingList.php
+++ b/framework/Web/UI/ActiveControls/TActiveRatingList.php
@@ -1,133 +1,133 @@
-
- * @author Bradley Booms
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveRatingList Class
- *
- * Displays clickable images that represent a TRadioButtonList
- *
- * @author Wei Zhuo
- * @author Bradley Booms
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveListControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- $this->setAdapter(new TActiveListControlAdapter($this));
- $this->setAutoPostBack(true);
- parent::__construct();
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- parent::setReadOnly($value);
- $value = $this->getReadOnly();
- $this->callClientFunction('setReadOnly',$value);
- }
-
- /**
- * @param float rating value, also sets the selected Index
- */
- public function setRating($value)
- {
- parent::setRating($value);
- $value = $this->getRating();
- $this->callClientFunction('setRating',$value);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $code = parent::getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
- }
-
- /**
- * @param string caption text
- */
- public function setCaption($value)
- {
- parent::setCaption($value);
- // if it's an active control, this should not be needed.
- $this->callClientFunction('setCaption',$value);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveRatingList';
- }
-}
-
+
+ * @author Bradley Booms
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveRatingList Class
+ *
+ * Displays clickable images that represent a TRadioButtonList
+ *
+ * @author Wei Zhuo
+ * @author Bradley Booms
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ parent::__construct();
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ parent::setReadOnly($value);
+ $value = $this->getReadOnly();
+ $this->callClientFunction('setReadOnly',$value);
+ }
+
+ /**
+ * @param float rating value, also sets the selected Index
+ */
+ public function setRating($value)
+ {
+ parent::setRating($value);
+ $value = $this->getRating();
+ $this->callClientFunction('setRating',$value);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = parent::getClientClassName().'.'.$func;
+ $client->callClientFunction($code,array($this,$value));
+ }
+ }
+
+ /**
+ * @param string caption text
+ */
+ public function setCaption($value)
+ {
+ parent::setCaption($value);
+ // if it's an active control, this should not be needed.
+ $this->callClientFunction('setCaption',$value);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveRatingList';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveTextBox.php b/framework/Web/UI/ActiveControls/TActiveTextBox.php
index 1e2fc46f..562f59cd 100644
--- a/framework/Web/UI/ActiveControls/TActiveTextBox.php
+++ b/framework/Web/UI/ActiveControls/TActiveTextBox.php
@@ -1,125 +1,125 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveTextBox class.
- *
- * TActiveTextBox allows the {@link setText Text} property of the textbox to
- * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
- * is true, changes to the textbox contents will perform a callback request causing
- * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
- * event.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client-side Text property can only be updated after the OnLoad stage.
- * @param string text content for the textbox
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
- $this->getPage()->getCallbackClient()->setValue($this, $value);
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveTextBox';
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveTextBox class.
+ *
+ * TActiveTextBox allows the {@link setText Text} property of the textbox to
+ * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
+ * is true, changes to the textbox contents will perform a callback request causing
+ * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
+ * event.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client-side Text property can only be updated after the OnLoad stage.
+ * @param string text content for the textbox
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
+ $this->getPage()->getCallbackClient()->setValue($this, $value);
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveTextBox';
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php
index 413d5c21..ce648b02 100644
--- a/framework/Web/UI/ActiveControls/TAutoComplete.php
+++ b/framework/Web/UI/ActiveControls/TAutoComplete.php
@@ -1,440 +1,440 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active text box.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TAutoComplete class.
- *
- * TAutoComplete is a textbox that provides a list of suggestion on
- * the current partial word typed in the textbox. The suggestions are
- * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
- * event. The events of the TActiveText (from which TAutoComplete is extended from)
- * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
- * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
- * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
- * vice versa.
- *
- * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
- * event handler. The partial word to match the suggestion is in the
- * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
- * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
- * method. This sets the datasource for the suggestions repeater, available through
- * the {@link getSuggestions Suggestions} property. Header, footer templates and
- * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
- * property and its sub-properties.
- *
- * The {@link setTextCssClass TextCssClass} property if set is used to find
- * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
- * that contains the actual text for the suggestion selected. That is,
- * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
- * will be used as suggestions.
- *
- * To return the list of suggestions back to the browser, supply a non-empty data source
- * and call databind. For example,
- *
- * function autocomplete_suggestion($sender, $param)
- * {
- * $token = $param->getToken(); //the partial word to match
- * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
- * $sender->dataBind();
- * }
- *
- *
- * The suggestion will be rendered when the {@link dataBind()} method is called
- * during a callback request .
- *
- * 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
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoComplete extends TActiveTextBox implements INamingContainer
-{
- /**
- * @var ITemplate template for repeater items
- */
- private $_repeater=null;
- /**
- * @var TPanel result panel holding the suggestion items.
- */
- private $_resultPanel=null;
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function getSeparator()
- {
- return $this->getViewState('tokens', '');
- }
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function setSeparator($value)
- {
- $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
- }
-
- /**
- * @return float maximum delay (in seconds) before requesting a suggestion.
- */
- public function getFrequency()
- {
- return $this->getViewState('frequency', '');
- }
-
- /**
- * @param float maximum delay (in seconds) before requesting a suggestion.
- * Default is 0.4.
- */
- public function setFrequency($value)
- {
- $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
- }
-
- /**
- * @return integer minimum number of characters before requesting a suggestion.
- */
- public function getMinChars()
- {
- return $this->getViewState('minChars','');
- }
-
- /**
- * @param integer minimum number of characters before requesting a suggestion.
- */
- public function setMinChars($value)
- {
- $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
- }
-
- /**
- * @param string Css class name of the element to use for suggestion.
- */
- public function setTextCssClass($value)
- {
- $this->setViewState('TextCssClass', $value);
- }
-
- /**
- * @return string Css class name of the element to use for suggestion.
- */
- public function getTextCssClass()
- {
- return $this->getViewState('TextCssClass');
- }
-
- /**
- * Raises the callback event. This method is overrides the parent implementation.
- * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
- * {@link onTextChanged OnTextChanged} event event and then the
- * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
- * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
- * and {@link onCallback OnCallback} events are NOT 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(''));
- $repeater->setFooterTemplate(new TAutoCompleteTemplate(' '));
- $repeater->setItemTemplate(new TTemplate('<%# $this->DataItem %> ',null));
- $this->getControls()->add($repeater);
- return $repeater;
- }
-
- /**
- * Renders the end tag and registers javascript effects library.
- */
- public function renderEndTag($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('effects');
- parent::renderEndTag($writer);
- $this->renderResultPanel($writer);
- }
-
- /**
- * Renders the result panel.
- * @param THtmlWriter the renderer.
- */
- protected function renderResultPanel($writer)
- {
- $this->getResultPanel()->render($writer);
- }
-
- /**
- * Renders the suggestions during a callback respones.
- * @param THtmlWriter the renderer.
- */
- public function renderCallback($writer)
- {
- $this->renderSuggestions($writer);
- }
-
- /**
- * Renders the suggestions repeater.
- * @param THtmlWriter the renderer.
- */
- public function renderSuggestions($writer)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $this->getSuggestions()->render($writer);
- $boundary = $writer->getWriter()->getBoundary();
- $this->getResponse()->getAdapter()->setResponseData($boundary);
- }
- }
-
- /**
- * @return array list of callback options.
- */
- protected function getPostBackOptions()
- {
- //disallow page state update ?
- //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
- $options = array();
- if(strlen($string = $this->getSeparator()))
- {
- $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
- $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
- $options['tokens'] = $token;
- }
- if($this->getAutoPostBack())
- {
- $options = array_merge($options,parent::getPostBackOptions());
- $options['AutoPostBack'] = true;
- }
- if(strlen($select = $this->getTextCssClass()))
- $options['select'] = $select;
- $options['ResultPanel'] = $this->getResultPanel()->getClientID();
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- if(($minchars=$this->getMinChars())!=='')
- $options['minChars'] = $minchars;
- if(($frequency=$this->getFrequency())!=='')
- $options['frequency'] = $frequency;
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- return $options;
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TAutoComplete';
- }
-}
-
-/**
- * TAutCompleteEventParameter contains the {@link getToken Token} requested by
- * the user for a partial match of the suggestions.
- *
- * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
- * suggestion selected by the user, -1 if not suggestion is selected.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteEventParameter extends TCallbackEventParameter
-{
- private $_selectedIndex=-1;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter, $index=-1)
- {
- parent::__construct($response, $parameter);
- $this->_selectedIndex=$index;
- }
-
- /**
- * @return int selected suggestion zero-based index, -1 if not selected.
- */
- public function getSelectedIndex()
- {
- return $this->_selectedIndex;
- }
-
- /**
- * @return string token for matching a list of suggestions.
- */
- public function getToken()
- {
- return $this->getCallbackParameter();
- }
-}
-
-/**
- * TAutoCompleteTemplate class.
- *
- * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
- * item template.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteTemplate extends TComponent implements ITemplate
-{
- private $_template;
-
- public function __construct($template)
- {
- $this->_template = $template;
- }
- /**
- * Instantiates the template.
- * It creates a {@link TDataList} control.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $parent->getControls()->add($this->_template);
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TAutoComplete class.
+ *
+ * TAutoComplete is a textbox that provides a list of suggestion on
+ * the current partial word typed in the textbox. The suggestions are
+ * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
+ * event. The events of the TActiveText (from which TAutoComplete is extended from)
+ * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
+ * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
+ * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
+ * vice versa.
+ *
+ * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
+ * event handler. The partial word to match the suggestion is in the
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
+ * method. This sets the datasource for the suggestions repeater, available through
+ * the {@link getSuggestions Suggestions} property. Header, footer templates and
+ * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
+ * property and its sub-properties.
+ *
+ * The {@link setTextCssClass TextCssClass} property if set is used to find
+ * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
+ * that contains the actual text for the suggestion selected. That is,
+ * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
+ * will be used as suggestions.
+ *
+ * To return the list of suggestions back to the browser, supply a non-empty data source
+ * and call databind. For example,
+ *
+ * function autocomplete_suggestion($sender, $param)
+ * {
+ * $token = $param->getToken(); //the partial word to match
+ * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
+ * $sender->dataBind();
+ * }
+ *
+ *
+ * The suggestion will be rendered when the {@link dataBind()} method is called
+ * during a callback request .
+ *
+ * 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
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoComplete extends TActiveTextBox implements INamingContainer
+{
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+ /**
+ * @var TPanel result panel holding the suggestion items.
+ */
+ private $_resultPanel=null;
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function getSeparator()
+ {
+ return $this->getViewState('tokens', '');
+ }
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function setSeparator($value)
+ {
+ $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
+ }
+
+ /**
+ * @return float maximum delay (in seconds) before requesting a suggestion.
+ */
+ public function getFrequency()
+ {
+ return $this->getViewState('frequency', '');
+ }
+
+ /**
+ * @param float maximum delay (in seconds) before requesting a suggestion.
+ * Default is 0.4.
+ */
+ public function setFrequency($value)
+ {
+ $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
+ }
+
+ /**
+ * @return integer minimum number of characters before requesting a suggestion.
+ */
+ public function getMinChars()
+ {
+ return $this->getViewState('minChars','');
+ }
+
+ /**
+ * @param integer minimum number of characters before requesting a suggestion.
+ */
+ public function setMinChars($value)
+ {
+ $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
+ }
+
+ /**
+ * @param string Css class name of the element to use for suggestion.
+ */
+ public function setTextCssClass($value)
+ {
+ $this->setViewState('TextCssClass', $value);
+ }
+
+ /**
+ * @return string Css class name of the element to use for suggestion.
+ */
+ public function getTextCssClass()
+ {
+ return $this->getViewState('TextCssClass');
+ }
+
+ /**
+ * Raises the callback event. This method is overrides the parent implementation.
+ * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
+ * {@link onTextChanged OnTextChanged} event event and then the
+ * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
+ * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
+ * and {@link onCallback OnCallback} events are NOT 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(''));
+ $repeater->setFooterTemplate(new TAutoCompleteTemplate(' '));
+ $repeater->setItemTemplate(new TTemplate('<%# $this->DataItem %> ',null));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+
+ /**
+ * Renders the end tag and registers javascript effects library.
+ */
+ public function renderEndTag($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('effects');
+ parent::renderEndTag($writer);
+ $this->renderResultPanel($writer);
+ }
+
+ /**
+ * Renders the result panel.
+ * @param THtmlWriter the renderer.
+ */
+ protected function renderResultPanel($writer)
+ {
+ $this->getResultPanel()->render($writer);
+ }
+
+ /**
+ * Renders the suggestions during a callback respones.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderCallback($writer)
+ {
+ $this->renderSuggestions($writer);
+ }
+
+ /**
+ * Renders the suggestions repeater.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderSuggestions($writer)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->getSuggestions()->render($writer);
+ $boundary = $writer->getWriter()->getBoundary();
+ $this->getResponse()->getAdapter()->setResponseData($boundary);
+ }
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ //disallow page state update ?
+ //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
+ $options = array();
+ if(strlen($string = $this->getSeparator()))
+ {
+ $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
+ $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
+ $options['tokens'] = $token;
+ }
+ if($this->getAutoPostBack())
+ {
+ $options = array_merge($options,parent::getPostBackOptions());
+ $options['AutoPostBack'] = true;
+ }
+ if(strlen($select = $this->getTextCssClass()))
+ $options['select'] = $select;
+ $options['ResultPanel'] = $this->getResultPanel()->getClientID();
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ if(($minchars=$this->getMinChars())!=='')
+ $options['minChars'] = $minchars;
+ if(($frequency=$this->getFrequency())!=='')
+ $options['frequency'] = $frequency;
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ return $options;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAutoComplete';
+ }
+}
+
+/**
+ * TAutCompleteEventParameter contains the {@link getToken Token} requested by
+ * the user for a partial match of the suggestions.
+ *
+ * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
+ * suggestion selected by the user, -1 if not suggestion is selected.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteEventParameter extends TCallbackEventParameter
+{
+ private $_selectedIndex=-1;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedIndex=$index;
+ }
+
+ /**
+ * @return int selected suggestion zero-based index, -1 if not selected.
+ */
+ public function getSelectedIndex()
+ {
+ return $this->_selectedIndex;
+ }
+
+ /**
+ * @return string token for matching a list of suggestions.
+ */
+ public function getToken()
+ {
+ return $this->getCallbackParameter();
+ }
+}
+
+/**
+ * TAutoCompleteTemplate class.
+ *
+ * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
+ * item template.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/framework/Web/UI/ActiveControls/TBaseActiveControl.php
index d3391b71..c412a2e2 100644
--- a/framework/Web/UI/ActiveControls/TBaseActiveControl.php
+++ b/framework/Web/UI/ActiveControls/TBaseActiveControl.php
@@ -1,392 +1,392 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TBaseActiveControl class provided additional basic property for every
- * active control. An instance of TBaseActiveControl or its decendent
- * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
- * method.
- *
- * The {@link setEnableUpdate EnableUpdate} property determines wether the active
- * control is allowed to update the contents of the client-side when the callback
- * response returns.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveControl extends TComponent
-{
- /**
- * @var TMap map of active control options.
- */
- private $_options;
- /**
- * @var TControl attached control.
- */
- private $_control;
-
- /**
- * Constructor. Attach a base active control to an active control instance.
- * @param TControl active control
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_options = new TMap;
- }
-
- /**
- * Sets a named options with a value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed new value.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function setOption($name,$value,$default=null)
- {
- $value = ($value===null) ? $default : $value;
- if($value!==null)
- $this->_options->add($name,$value);
- }
-
- /**
- * Gets an option named value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function getOption($name,$default=null)
- {
- $item = $this->_options->itemAt($name);
- return ($item===null) ? $default : $item;
- }
-
- /**
- * @return TMap active control options
- */
- protected function getOptions()
- {
- return $this->_options;
- }
-
- /**
- * @return TPage the page containing the attached control.
- */
- protected function getPage()
- {
- return $this->_control->getPage();
- }
-
- /**
- * @return TControl the attached control.
- */
- protected function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @param boolean true to allow fine grain callback updates.
- */
- public function setEnableUpdate($value)
- {
- $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true to allow fine grain callback updates.
- */
- public function getEnableUpdate()
- {
- return $this->getOption('EnableUpdate', true);
- }
-
- /**
- * Returns true if callback response is allowed to update the browser contents.
- * Is is true if the control is initilized, and is a callback request and
- * the {@link setEnableUpdate EnableUpdate} property is true and
- * the page is not loading post data.
- * @return boolean true if the callback response is allowed update
- * client-side contents.
- */
- public function canUpdateClientSide($bDontRequireVisibility=false)
- {
- return $this->getControl()->getHasChildInitialized()
- && $this->getPage()->getIsLoadingPostData() == false
- && $this->getPage()->getIsCallback()
- && $this->getEnableUpdate()
- && ($bDontRequireVisibility || $this->getControl()->getVisible());
- }
-}
-
-/**
- * TBaseActiveCallbackControl is a common set of options and functionality for
- * active controls that can perform callback requests.
- *
- * The properties of TBaseActiveCallbackControl can be accessed and changed from
- * each individual active controls' {@link getActiveControl ActiveControl}
- * property.
- *
- * The following example sets the validation group property of a TCallback component.
- *
- *
- *
- *
- * 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.
- *
- *
- *
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveCallbackControl extends TBaseActiveControl
-{
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g.
- * See {@link TCallbackClientSide} for details on the properties of ClientSide.
- * @return TCallbackClientSide client-side callback options.
- */
- public function getClientSide()
- {
- if(($client = $this->getOption('ClientSide'))===null)
- {
- $client = $this->createClientSide();
- $this->setOption('ClientSide', $client);
- }
- return $client;
- }
-
- /**
- * Sets the client side options. Can only be set when client side is null.
- * @param TCallbackClientSide client side options.
- */
- public function setClientSide($client)
- {
- if( $this->getOption('ClientSide')===null)
- $this->setOption('ClientSide', $client);
- else
- throw new TConfigurationException(
- 'active_controls_client_side_exists', $this->getControl()->getID());
- }
-
- /**
- * @return TCallbackClientSide callback client-side options.
- */
- protected function createClientSide()
- {
- return new TCallbackClientSide;
- }
-
- /**
- * Sets default callback options. Takes the ID of a TCallbackOptions
- * component to duplicate the client-side
- * options for this control. The {@link getClientSide ClientSide}
- * subproperties takes precedence over the CallbackOptions property.
- * @param string ID of a TCallbackOptions control from which ClientSide
- * options are cloned.
- */
- public function setCallbackOptions($value)
- {
- $this->setOption('CallbackOptions', $value, '');
- }
-
- /**
- * @return string ID of a TCallbackOptions control from which ClientSide
- * options are duplicated.
- */
- public function getCallbackOptions()
- {
- return $this->getOption('CallbackOptions', '');
- }
-
- /**
- * Returns an array of default callback client-side options. The default options
- * are obtained from the client-side options of a TCallbackOptions control with
- * ID specified by {@link setCallbackOptions CallbackOptions}.
- * @return array list of default callback client-side options.
- */
- protected function getDefaultClientSideOptions()
- {
- if(($id=$this->getCallbackOptions())!=='')
- {
- if(($pos=strrpos($id,'.'))!==false)
- {
- $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
- $newid=substr($id,$pos+1);
- if ($control!==null)
- $control=$control->$newid;
- }
- else
- {
- $control=$this->getControl()->findControl($id);
- }
-
- if($control instanceof TCallbackOptions)
- return $control->getClientSide()->getOptions()->toArray();
- else
- throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
- }
-
- return array();
- }
-
- /**
- * @return boolean whether callback event trigger by this button will cause
- * input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getOption('CausesValidation',true);
- }
-
- /**
- * @param boolean whether callback event trigger by this button will cause
- * input validation
- */
- public function setCausesValidation($value)
- {
- $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation
- * upon callback
- */
- public function getValidationGroup()
- {
- return $this->getOption('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation
- * upon callback
- */
- public function setValidationGroup($value)
- {
- $this->setOption('ValidationGroup',$value,'');
- }
-
- /**
- * @return boolean whether to perform validation if the callback is
- * requested.
- */
- public function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param mixed callback parameter value.
- */
- public function setCallbackParameter($value)
- {
- $this->setOption('CallbackParameter', $value, '');
- }
-
- /**
- * @return mixed callback parameter value.
- */
- public function getCallbackParameter()
- {
- return $this->getOption('CallbackParameter', '');
- }
-
-
- /**
- * @return array list of callback javascript options.
- */
- protected function getClientSideOptions()
- {
- $default = $this->getDefaultClientSideOptions();
- $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
- $validate = $this->getCausesValidation();
- $options['CausesValidation']= $validate ? '' : false;
- $options['ValidationGroup']=$this->getValidationGroup();
- $options['CallbackParameter'] = $this->getCallbackParameter();
- return $options;
- }
-
- /**
- * Registers the callback control javascript code. Client-side options are
- * merged and passed to the javascript code. This method should be called by
- * Active component developers wanting to register the javascript to initialize
- * the active component with additional options offered by the
- * {@link getClientSide ClientSide} property.
- * @param string client side javascript class name.
- * @param array additional callback options.
- */
- public function registerCallbackClientScript($class,$options=null)
- {
- $cs = $this->getPage()->getClientScript();
- if(is_array($options))
- $options = array_merge($this->getClientSideOptions(),$options);
- else
- $options = $this->getClientSideOptions();
-
- //remove true as default to save bytes
- if($options['CausesValidation']===true)
- $options['CausesValidation']='';
- $cs->registerCallbackControl($class, $options);
- }
-
- /**
- * Returns the javascript callback request instance. To invoke a callback
- * request for this control call the dispatch() method on the
- * request instance. Example code in javascript
- *
- * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
- * request.setParameter('hello');
- * request.dispatch(); //make the callback request.
- *
- *
- * Alternatively,
- *
- * //dispatches immediately
- * Prado.Callback("<%= $this->mycallback->UniqueID %>",
- * $this->mycallback->ActiveControl->JsCallbackOptions);
- *
- * @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());
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TBaseActiveControl class provided additional basic property for every
+ * active control. An instance of TBaseActiveControl or its decendent
+ * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
+ * method.
+ *
+ * The {@link setEnableUpdate EnableUpdate} property determines wether the active
+ * control is allowed to update the contents of the client-side when the callback
+ * response returns.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveControl extends TComponent
+{
+ /**
+ * @var TMap map of active control options.
+ */
+ private $_options;
+ /**
+ * @var TControl attached control.
+ */
+ private $_control;
+
+ /**
+ * Constructor. Attach a base active control to an active control instance.
+ * @param TControl active control
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_options = new TMap;
+ }
+
+ /**
+ * Sets a named options with a value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed new value.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function setOption($name,$value,$default=null)
+ {
+ $value = ($value===null) ? $default : $value;
+ if($value!==null)
+ $this->_options->add($name,$value);
+ }
+
+ /**
+ * Gets an option named value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function getOption($name,$default=null)
+ {
+ $item = $this->_options->itemAt($name);
+ return ($item===null) ? $default : $item;
+ }
+
+ /**
+ * @return TMap active control options
+ */
+ protected function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * @return TPage the page containing the attached control.
+ */
+ protected function getPage()
+ {
+ return $this->_control->getPage();
+ }
+
+ /**
+ * @return TControl the attached control.
+ */
+ protected function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @param boolean true to allow fine grain callback updates.
+ */
+ public function setEnableUpdate($value)
+ {
+ $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true to allow fine grain callback updates.
+ */
+ public function getEnableUpdate()
+ {
+ return $this->getOption('EnableUpdate', true);
+ }
+
+ /**
+ * Returns true if callback response is allowed to update the browser contents.
+ * Is is true if the control is initilized, and is a callback request and
+ * the {@link setEnableUpdate EnableUpdate} property is true and
+ * the page is not loading post data.
+ * @return boolean true if the callback response is allowed update
+ * client-side contents.
+ */
+ public function canUpdateClientSide($bDontRequireVisibility=false)
+ {
+ return $this->getControl()->getHasChildInitialized()
+ && $this->getPage()->getIsLoadingPostData() == false
+ && $this->getPage()->getIsCallback()
+ && $this->getEnableUpdate()
+ && ($bDontRequireVisibility || $this->getControl()->getVisible());
+ }
+}
+
+/**
+ * TBaseActiveCallbackControl is a common set of options and functionality for
+ * active controls that can perform callback requests.
+ *
+ * The properties of TBaseActiveCallbackControl can be accessed and changed from
+ * each individual active controls' {@link getActiveControl ActiveControl}
+ * property.
+ *
+ * The following example sets the validation group property of a TCallback component.
+ *
+ *
+ *
+ *
+ * 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.
+ *
+ *
+ *
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveCallbackControl extends TBaseActiveControl
+{
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g.
+ * See {@link TCallbackClientSide} for details on the properties of ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if(($client = $this->getOption('ClientSide'))===null)
+ {
+ $client = $this->createClientSide();
+ $this->setOption('ClientSide', $client);
+ }
+ return $client;
+ }
+
+ /**
+ * Sets the client side options. Can only be set when client side is null.
+ * @param TCallbackClientSide client side options.
+ */
+ public function setClientSide($client)
+ {
+ if( $this->getOption('ClientSide')===null)
+ $this->setOption('ClientSide', $client);
+ else
+ throw new TConfigurationException(
+ 'active_controls_client_side_exists', $this->getControl()->getID());
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return new TCallbackClientSide;
+ }
+
+ /**
+ * Sets default callback options. Takes the ID of a TCallbackOptions
+ * component to duplicate the client-side
+ * options for this control. The {@link getClientSide ClientSide}
+ * subproperties takes precedence over the CallbackOptions property.
+ * @param string ID of a TCallbackOptions control from which ClientSide
+ * options are cloned.
+ */
+ public function setCallbackOptions($value)
+ {
+ $this->setOption('CallbackOptions', $value, '');
+ }
+
+ /**
+ * @return string ID of a TCallbackOptions control from which ClientSide
+ * options are duplicated.
+ */
+ public function getCallbackOptions()
+ {
+ return $this->getOption('CallbackOptions', '');
+ }
+
+ /**
+ * Returns an array of default callback client-side options. The default options
+ * are obtained from the client-side options of a TCallbackOptions control with
+ * ID specified by {@link setCallbackOptions CallbackOptions}.
+ * @return array list of default callback client-side options.
+ */
+ protected function getDefaultClientSideOptions()
+ {
+ if(($id=$this->getCallbackOptions())!=='')
+ {
+ if(($pos=strrpos($id,'.'))!==false)
+ {
+ $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
+ $newid=substr($id,$pos+1);
+ if ($control!==null)
+ $control=$control->$newid;
+ }
+ else
+ {
+ $control=$this->getControl()->findControl($id);
+ }
+
+ if($control instanceof TCallbackOptions)
+ return $control->getClientSide()->getOptions()->toArray();
+ else
+ throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
+ }
+
+ return array();
+ }
+
+ /**
+ * @return boolean whether callback event trigger by this button will cause
+ * input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getOption('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether callback event trigger by this button will cause
+ * input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getOption('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setOption('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether to perform validation if the callback is
+ * requested.
+ */
+ public function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param mixed callback parameter value.
+ */
+ public function setCallbackParameter($value)
+ {
+ $this->setOption('CallbackParameter', $value, '');
+ }
+
+ /**
+ * @return mixed callback parameter value.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->getOption('CallbackParameter', '');
+ }
+
+
+ /**
+ * @return array list of callback javascript options.
+ */
+ protected function getClientSideOptions()
+ {
+ $default = $this->getDefaultClientSideOptions();
+ $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
+ $validate = $this->getCausesValidation();
+ $options['CausesValidation']= $validate ? '' : false;
+ $options['ValidationGroup']=$this->getValidationGroup();
+ $options['CallbackParameter'] = $this->getCallbackParameter();
+ return $options;
+ }
+
+ /**
+ * Registers the callback control javascript code. Client-side options are
+ * merged and passed to the javascript code. This method should be called by
+ * Active component developers wanting to register the javascript to initialize
+ * the active component with additional options offered by the
+ * {@link getClientSide ClientSide} property.
+ * @param string client side javascript class name.
+ * @param array additional callback options.
+ */
+ public function registerCallbackClientScript($class,$options=null)
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(is_array($options))
+ $options = array_merge($this->getClientSideOptions(),$options);
+ else
+ $options = $this->getClientSideOptions();
+
+ //remove true as default to save bytes
+ if($options['CausesValidation']===true)
+ $options['CausesValidation']='';
+ $cs->registerCallbackControl($class, $options);
+ }
+
+ /**
+ * Returns the javascript callback request instance. To invoke a callback
+ * request for this control call the dispatch() method on the
+ * request instance. Example code in javascript
+ *
+ * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
+ * request.setParameter('hello');
+ * request.dispatch(); //make the callback request.
+ *
+ *
+ * Alternatively,
+ *
+ * //dispatches immediately
+ * Prado.Callback("<%= $this->mycallback->UniqueID %>",
+ * $this->mycallback->ActiveControl->JsCallbackOptions);
+ *
+ * @return string javascript client-side callback request object (javascript
+ * code)
+ */
+ public function getJavascript()
+ {
+ $client = $this->getPage()->getClientScript();
+ return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions());
+ }
+
+ /**
+ * @param string callback requestion options as javascript code.
+ */
+ public function getJsCallbackOptions()
+ {
+ return TJavaScript::encode($this->getClientSideOptions());
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php
index 7a1f54b7..662bc03f 100644
--- a/framework/Web/UI/ActiveControls/TCallback.php
+++ b/framework/Web/UI/ActiveControls/TCallback.php
@@ -1,101 +1,101 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TCallback component class.
- *
- * The TCallback provides a basic callback handler that can be invoked from the
- * client side by running the javascript code obtained from the
- * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
- * The event {@link onCallback OnCallback} is raised when a callback is requested made.
- *
- * Example usage:
- *
- *
- *
- * Click Me!
- *
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, call this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
- * {@link getCausesValidation ActiveControl.CausesValidation} is true,
- * it will invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onCallback OnCallback} event. This method is mainly
- * used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- if($this->getActiveControl()->canCauseValidation())
- $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TCallback component class.
+ *
+ * The TCallback provides a basic callback handler that can be invoked from the
+ * client side by running the javascript code obtained from the
+ * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
+ * The event {@link onCallback OnCallback} is raised when a callback is requested made.
+ *
+ * Example usage:
+ *
+ *
+ *
+ * Click Me!
+ *
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, call this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
+ * {@link getCausesValidation ActiveControl.CausesValidation} is true,
+ * it will invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onCallback OnCallback} event. This method is mainly
+ * used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ if($this->getActiveControl()->canCauseValidation())
+ $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
index 6dcbe3d0..291f22f2 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
@@ -1,705 +1,705 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientScript class.
- *
- * The TCallbackClientScript class provides corresponding methods that can be
- * executed on the client-side (i.e. the browser client that is viewing
- * the page) during a callback response.
- *
- * The avaiable methods includes setting/clicking input elements, changing Css
- * styles, hiding/showing elements, and adding visual effects to elements on the
- * page. The client-side methods can be access through the CallbackClient
- * property available in TPage.
- *
- * For example, to hide "$myTextBox" element during callback response, do
- *
- * $this->getPage()->getCallbackClient()->hide($myTextBox);
- *
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientScript extends TApplicationComponent
-{
- /**
- * @var TList list of client functions to execute.
- */
- private $_actions;
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- $this->_actions = new TList;
- }
-
- /**
- * @return array list of client function to be executed during callback
- * response.
- */
- public function getClientFunctionsToExecute()
- {
- return $this->_actions->toArray();
- }
-
- /**
- * Executes a client-side statement.
- * @param string javascript function name
- * @param array list of arguments for the function
- */
- public function callClientFunction($function, $params=null)
- {
- if(!is_array($params))
- $params = array($params);
-
- if(count($params) > 0)
- {
- if($params[0] instanceof TControl)
- $params[0] = $params[0]->getClientID();
- }
- $this->_actions->add(array($function => $params));
- }
-
- /**
- * Client script to set the value of a particular input element.
- * @param TControl control element to set the new value
- * @param string new value
- */
- public function setValue($input, $text)
- {
- $this->callClientFunction('Prado.Element.setValue', array($input, $text));
- }
-
- /**
- * Client script to select/clear/check a drop down list, check box list,
- * or radio button list.
- * The second parameter determines the selection method. Valid methods are
- * - Value , select or check by value
- * - Values , select or check by a list of values
- * - Index , select or check by index (zero based index)
- * - Indices , select or check by a list of index (zero based index)
- * - Clear , clears or selections or checks in the list
- * - All , select all
- * - Invert , invert the selection.
- * @param TControl list control
- * @param string selection method
- * @param string|int the value or index to select/check.
- * @param string selection control type, either 'check' or 'select'
- */
- public function select($control, $method='Value', $value=null, $type=null)
- {
- $method = TPropertyValue::ensureEnum($method,
- 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
- $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
- $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
- $this->callClientFunction('Prado.Element.select',
- array($control, $type.$method, $value, $total));
- }
-
- private function getSelectionControlType($control)
- {
- if(is_string($control)) return 'check';
- if($control instanceof TCheckBoxList)
- return 'check';
- if($control instanceof TCheckBox)
- return 'check';
- return 'select';
- }
-
- private function getSelectionControlIsListType($control)
- {
- return $control instanceof TListControl;
- }
-
- /**
- * Client script to click on an element. This client-side function is unpredictable.
- *
- * @param TControl control element or element id
- */
- public function click($control)
- {
- $this->callClientFunction('Prado.Element.click', $control);
- }
-
- /**
- * Client script to check or uncheck a checkbox or radio button.
- * @param TControl control element or element id
- * @param boolean check or uncheck the checkbox or radio button.
- */
- public function check($checkbox, $checked=true)
- {
- $this->select($checkbox, "Value", $checked);
- }
-
- /**
- * Raise the client side event (given by $eventName) on a particular element.
- * @param TControl control element or element id
- * @param string Event name, e.g. "click"
- */
- public function raiseClientEvent($control, $eventName)
- {
- $this->callClientFunction('Event.fireEvent',
- array($control, strtolower($eventName)));
- }
-
- /**
- * Sets the attribute of a particular control.
- * @param TControl control element or element id
- * @param string attribute name
- * @param string attribute value
- */
- public function setAttribute($control, $name, $value)
- {
- // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
- if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
- $control=$control->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
- }
-
- /**
- * Sets the options of a select input element.
- * @param TControl control element or element id
- * @param TCollection a list of new options
- */
- public function setListItems($control, $items)
- {
- $options = array();
- if($control instanceof TListControl)
- {
- $promptText = $control->getPromptText();
- $promptValue = $control->getPromptValue();
-
- if($promptValue==='')
- $promptValue = $promptText;
-
- if($promptValue!=='')
- $options[] = array($promptText, $promptValue);
- }
-
- foreach($items as $item)
- {
- if($item->getHasAttributes())
- $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
- else
- $options[] = array($item->getText(),$item->getValue());
- }
- $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
- }
-
- /**
- * Shows an element by changing its CSS display style as empty.
- * @param TControl control element or element id
- */
- public function show($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.show', $element);
- }
-
- /**
- * Hides an element by changing its CSS display style to "none".
- * @param TControl control element or element id
- */
- public function hide($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.hide', $element);
- }
-
- /**
- * Toggles the visibility of the element.
- * @param TControl control element or element id
- * @param string visual effect, such as, 'appear' or 'slide' or 'blind'.
- * @param array additional options.
- */
- public function toggle($element, $effect=null, $options=array())
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.toggle', array($element,$effect,$options));
- }
-
- /**
- * Removes an element from the HTML page.
- * @param TControl control element or element id
- */
- public function remove($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.remove', $element);
- }
-
- public function addPostDataLoader($name)
- {
- $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name);
- }
-
- /**
- * Update the element's innerHTML with new content.
- * @param TControl control element or element id
- * @param TControl new HTML content, if content is of a TControl, the
- * controls render method is called.
- */
- public function update($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Element.update');
- }
-
- /**
- * Add a Css class name to the element.
- * @param TControl control element or element id
- * @param string CssClass name to add.
- */
- public function addCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.addClassName', array($element, $cssClass));
- }
-
- /**
- * Remove a Css class name from the element.
- * @param TControl control element or element id
- * @param string CssClass name to remove.
- */
- public function removeCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.removeClassName', array($element, $cssClass));
- }
-
- /**
- * Sets the CssClass of an element.
- * @param TControl control element or element id
- * @param string new CssClass name for the element.
- */
- /*public function setCssClass($element, $cssClass)
- {
- $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass));
- }*/
-
- /**
- * Scroll the top of the browser viewing area to the location of the
- * element.
- * @param TControl control element or element id
- */
- public function scrollTo($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.scrollTo', $element);
- }
-
- /**
- * Focus on a particular element.
- * @param TControl control element or element id.
- */
- public function focus($element)
- {
- $this->callClientFunction('Prado.Element.focus', $element);
- }
-
- /**
- * Sets the style of element. The style must be a key-value array where the
- * key is the style property and the value is the style value.
- * @param TControl control element or element id
- * @param array list of key-value pairs as style property and style value.
- */
- public function setStyle($element, $styles)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setStyle', array($element, $styles));
- }
-
- /**
- * Append a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function appendContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.append');
- }
-
- /**
- * Prepend a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function prependContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.prepend');
- }
-
- /**
- * Insert a HTML fragement after the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentAfter($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.after');
- }
-
- /**
- * Insert a HTML fragement in before the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentBefore($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.before');
- }
-
- /**
- * Replace the content of an element with new content. The new content can
- * be a string or a TControl component. If the content parameter is
- * a TControl component, its rendered method will be called and its contents
- * will be used for replacement.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- * @param string replacement method, default is to replace the outter
- * html content.
- * @param string provide a custom boundary.
- * @see insertAbout
- * @see insertBelow
- * @see insertBefore
- * @see insertAfter
- */
- protected function replace($element, $content, $method="Element.replace", $boundary=null)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- $content = null;
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- $content = null;
- }
-
- $this->callClientFunction('Prado.Element.replace',
- array($element, $method, $content, $boundary));
- }
-
- /**
- * Replace the content of an element with new content contained in writer.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- */
- public function replaceContent($element,$content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content);
- }
-
- /**
- * Evaluate a block of javascript enclosed in a boundary.
- * @param THtmlWriter writer for the content.
- */
- public function evaluateScript($writer)
- {
- $this->replace(null, $writer, 'Prado.Element.evaluateScript');
- }
-
- /**
- * Appends a block of inline javascript enclosed in a boundary.
- * Similar to to evaluateScript(), but functions declared in the
- * inline block will be available to page elements.
- * @param THtmlWriter writer for the content.
- */
- public function appendScriptBlock($content)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- }
-
- $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
- }
-
- /**
- * Renders the control and return the content boundary from
- * TCallbackResponseWriter. This method should only be used by framework
- * component developers. The render() method is defered to be called in the
- * TActivePageAdapter class.
- * @param TControl control to be rendered on callback response.
- * @return string the boundary for which the rendered content is wrapped.
- */
- private function getRenderedContentBoundary($control)
- {
- $writer = $this->getResponse()->createHtmlWriter();
- $adapter = $control->getPage()->getAdapter();
- $adapter->registerControlToRender($control, $writer);
- return $writer->getWriter()->getBoundary();
- }
-
- /**
- * @param THtmlWriter the writer responsible for rendering html content.
- * @return string content boundary.
- */
- private function getResponseContentBoundary($html)
- {
- if($html instanceof THtmlWriter)
- {
- if($html->getWriter() instanceof TCallbackResponseWriter)
- return $html->getWriter()->getBoundary();
- }
- return null;
- }
-
- /**
- * Add a visual effect the element.
- * @param string visual effect function name.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function visualEffect($type, $element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction($type, array($element, $options));
- }
-
- /**
- * Visual Effect: Gradually make the element appear.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function appear($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Appear', $element, $options);
- }
-
- /**
- * Visual Effect: Blind down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindDown', $element, $options);
- }
-
- /**
- * Visual Effect: Blind up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindUp', $element, $options);
-
- }
-
- /**
- * Visual Effect: Drop out.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function dropOut($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.DropOut', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fade($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fade', $element, $options);
- }
-
- /**
- * Visual Effect: Fold.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fold($element, $options = null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fold', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually make an element grow to a predetermined size.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function grow($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Grow', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually grow and fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function puff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Puff', $element, $options);
- }
-
- /**
- * Visual Effect: Pulsate.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function pulsate($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Pulsate', $element, $options);
- }
-
- /**
- * Visual Effect: Shake the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shake($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shake', $element, $options);
- }
-
- /**
- * Visual Effect: Shrink the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shrink($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shrink', $element, $options);
- }
-
- /**
- * Visual Effect: Slide down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideDown', $element, $options);
- }
-
- /**
- * Visual Effect: Side up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideUp', $element, $options);
- }
-
- /**
- * Visual Effect: Squish the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function squish($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Squish', $element, $options);
- }
-
- /**
- * Visual Effect: Switch Off effect.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function switchOff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SwitchOff', $element, $options);
- }
-
- /**
- * Visual Effect: High light the element for about 2 seconds.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function highlight($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Prado.Effect.Highlight', $element, $options);
- }
-
- /**
- * Set the opacity on a html element or control.
- * @param TControl control element or element id
- * @param float opacity value between 1 and 0
- */
- public function setOpacity($element, $value)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $value = TPropertyValue::ensureFloat($value);
- $this->callClientFunction('Element.setOpacity', array($element,$value));
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientScript class.
+ *
+ * The TCallbackClientScript class provides corresponding methods that can be
+ * executed on the client-side (i.e. the browser client that is viewing
+ * the page) during a callback response.
+ *
+ * The avaiable methods includes setting/clicking input elements, changing Css
+ * styles, hiding/showing elements, and adding visual effects to elements on the
+ * page. The client-side methods can be access through the CallbackClient
+ * property available in TPage.
+ *
+ * For example, to hide "$myTextBox" element during callback response, do
+ *
+ * $this->getPage()->getCallbackClient()->hide($myTextBox);
+ *
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientScript extends TApplicationComponent
+{
+ /**
+ * @var TList list of client functions to execute.
+ */
+ private $_actions;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->_actions = new TList;
+ }
+
+ /**
+ * @return array list of client function to be executed during callback
+ * response.
+ */
+ public function getClientFunctionsToExecute()
+ {
+ return $this->_actions->toArray();
+ }
+
+ /**
+ * Executes a client-side statement.
+ * @param string javascript function name
+ * @param array list of arguments for the function
+ */
+ public function callClientFunction($function, $params=null)
+ {
+ if(!is_array($params))
+ $params = array($params);
+
+ if(count($params) > 0)
+ {
+ if($params[0] instanceof TControl)
+ $params[0] = $params[0]->getClientID();
+ }
+ $this->_actions->add(array($function => $params));
+ }
+
+ /**
+ * Client script to set the value of a particular input element.
+ * @param TControl control element to set the new value
+ * @param string new value
+ */
+ public function setValue($input, $text)
+ {
+ $this->callClientFunction('Prado.Element.setValue', array($input, $text));
+ }
+
+ /**
+ * Client script to select/clear/check a drop down list, check box list,
+ * or radio button list.
+ * The second parameter determines the selection method. Valid methods are
+ * - Value , select or check by value
+ * - Values , select or check by a list of values
+ * - Index , select or check by index (zero based index)
+ * - Indices , select or check by a list of index (zero based index)
+ * - Clear , clears or selections or checks in the list
+ * - All , select all
+ * - Invert , invert the selection.
+ * @param TControl list control
+ * @param string selection method
+ * @param string|int the value or index to select/check.
+ * @param string selection control type, either 'check' or 'select'
+ */
+ public function select($control, $method='Value', $value=null, $type=null)
+ {
+ $method = TPropertyValue::ensureEnum($method,
+ 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
+ $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
+ $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
+ $this->callClientFunction('Prado.Element.select',
+ array($control, $type.$method, $value, $total));
+ }
+
+ private function getSelectionControlType($control)
+ {
+ if(is_string($control)) return 'check';
+ if($control instanceof TCheckBoxList)
+ return 'check';
+ if($control instanceof TCheckBox)
+ return 'check';
+ return 'select';
+ }
+
+ private function getSelectionControlIsListType($control)
+ {
+ return $control instanceof TListControl;
+ }
+
+ /**
+ * Client script to click on an element. This client-side function is unpredictable.
+ *
+ * @param TControl control element or element id
+ */
+ public function click($control)
+ {
+ $this->callClientFunction('Prado.Element.click', $control);
+ }
+
+ /**
+ * Client script to check or uncheck a checkbox or radio button.
+ * @param TControl control element or element id
+ * @param boolean check or uncheck the checkbox or radio button.
+ */
+ public function check($checkbox, $checked=true)
+ {
+ $this->select($checkbox, "Value", $checked);
+ }
+
+ /**
+ * Raise the client side event (given by $eventName) on a particular element.
+ * @param TControl control element or element id
+ * @param string Event name, e.g. "click"
+ */
+ public function raiseClientEvent($control, $eventName)
+ {
+ $this->callClientFunction('Event.fireEvent',
+ array($control, strtolower($eventName)));
+ }
+
+ /**
+ * Sets the attribute of a particular control.
+ * @param TControl control element or element id
+ * @param string attribute name
+ * @param string attribute value
+ */
+ public function setAttribute($control, $name, $value)
+ {
+ // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
+ if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
+ $control=$control->getSurroundingTagID();
+ $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
+ }
+
+ /**
+ * Sets the options of a select input element.
+ * @param TControl control element or element id
+ * @param TCollection a list of new options
+ */
+ public function setListItems($control, $items)
+ {
+ $options = array();
+ if($control instanceof TListControl)
+ {
+ $promptText = $control->getPromptText();
+ $promptValue = $control->getPromptValue();
+
+ if($promptValue==='')
+ $promptValue = $promptText;
+
+ if($promptValue!=='')
+ $options[] = array($promptText, $promptValue);
+ }
+
+ foreach($items as $item)
+ {
+ if($item->getHasAttributes())
+ $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
+ else
+ $options[] = array($item->getText(),$item->getValue());
+ }
+ $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
+ }
+
+ /**
+ * Shows an element by changing its CSS display style as empty.
+ * @param TControl control element or element id
+ */
+ public function show($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.show', $element);
+ }
+
+ /**
+ * Hides an element by changing its CSS display style to "none".
+ * @param TControl control element or element id
+ */
+ public function hide($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.hide', $element);
+ }
+
+ /**
+ * Toggles the visibility of the element.
+ * @param TControl control element or element id
+ * @param string visual effect, such as, 'appear' or 'slide' or 'blind'.
+ * @param array additional options.
+ */
+ public function toggle($element, $effect=null, $options=array())
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.toggle', array($element,$effect,$options));
+ }
+
+ /**
+ * Removes an element from the HTML page.
+ * @param TControl control element or element id
+ */
+ public function remove($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.remove', $element);
+ }
+
+ public function addPostDataLoader($name)
+ {
+ $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name);
+ }
+
+ /**
+ * Update the element's innerHTML with new content.
+ * @param TControl control element or element id
+ * @param TControl new HTML content, if content is of a TControl, the
+ * controls render method is called.
+ */
+ public function update($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Element.update');
+ }
+
+ /**
+ * Add a Css class name to the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to add.
+ */
+ public function addCssClass($element, $cssClass)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.addClassName', array($element, $cssClass));
+ }
+
+ /**
+ * Remove a Css class name from the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to remove.
+ */
+ public function removeCssClass($element, $cssClass)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.removeClassName', array($element, $cssClass));
+ }
+
+ /**
+ * Sets the CssClass of an element.
+ * @param TControl control element or element id
+ * @param string new CssClass name for the element.
+ */
+ /*public function setCssClass($element, $cssClass)
+ {
+ $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass));
+ }*/
+
+ /**
+ * Scroll the top of the browser viewing area to the location of the
+ * element.
+ * @param TControl control element or element id
+ */
+ public function scrollTo($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.scrollTo', $element);
+ }
+
+ /**
+ * Focus on a particular element.
+ * @param TControl control element or element id.
+ */
+ public function focus($element)
+ {
+ $this->callClientFunction('Prado.Element.focus', $element);
+ }
+
+ /**
+ * Sets the style of element. The style must be a key-value array where the
+ * key is the style property and the value is the style value.
+ * @param TControl control element or element id
+ * @param array list of key-value pairs as style property and style value.
+ */
+ public function setStyle($element, $styles)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Prado.Element.setStyle', array($element, $styles));
+ }
+
+ /**
+ * Append a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function appendContent($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.append');
+ }
+
+ /**
+ * Prepend a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function prependContent($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.prepend');
+ }
+
+ /**
+ * Insert a HTML fragement after the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentAfter($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.after');
+ }
+
+ /**
+ * Insert a HTML fragement in before the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentBefore($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.before');
+ }
+
+ /**
+ * Replace the content of an element with new content. The new content can
+ * be a string or a TControl component. If the content parameter is
+ * a TControl component, its rendered method will be called and its contents
+ * will be used for replacement.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered
+ * @param string replacement method, default is to replace the outter
+ * html content.
+ * @param string provide a custom boundary.
+ * @see insertAbout
+ * @see insertBelow
+ * @see insertBefore
+ * @see insertAfter
+ */
+ protected function replace($element, $content, $method="Element.replace", $boundary=null)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ $content = null;
+ }
+ else if($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ $content = null;
+ }
+
+ $this->callClientFunction('Prado.Element.replace',
+ array($element, $method, $content, $boundary));
+ }
+
+ /**
+ * Replace the content of an element with new content contained in writer.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function replaceContent($element,$content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content);
+ }
+
+ /**
+ * Evaluate a block of javascript enclosed in a boundary.
+ * @param THtmlWriter writer for the content.
+ */
+ public function evaluateScript($writer)
+ {
+ $this->replace(null, $writer, 'Prado.Element.evaluateScript');
+ }
+
+ /**
+ * Appends a block of inline javascript enclosed in a boundary.
+ * Similar to to evaluateScript(), but functions declared in the
+ * inline block will be available to page elements.
+ * @param THtmlWriter writer for the content.
+ */
+ public function appendScriptBlock($content)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ }
+ else if($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ }
+
+ $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
+ }
+
+ /**
+ * Renders the control and return the content boundary from
+ * TCallbackResponseWriter. This method should only be used by framework
+ * component developers. The render() method is defered to be called in the
+ * TActivePageAdapter class.
+ * @param TControl control to be rendered on callback response.
+ * @return string the boundary for which the rendered content is wrapped.
+ */
+ private function getRenderedContentBoundary($control)
+ {
+ $writer = $this->getResponse()->createHtmlWriter();
+ $adapter = $control->getPage()->getAdapter();
+ $adapter->registerControlToRender($control, $writer);
+ return $writer->getWriter()->getBoundary();
+ }
+
+ /**
+ * @param THtmlWriter the writer responsible for rendering html content.
+ * @return string content boundary.
+ */
+ private function getResponseContentBoundary($html)
+ {
+ if($html instanceof THtmlWriter)
+ {
+ if($html->getWriter() instanceof TCallbackResponseWriter)
+ return $html->getWriter()->getBoundary();
+ }
+ return null;
+ }
+
+ /**
+ * Add a visual effect the element.
+ * @param string visual effect function name.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function visualEffect($type, $element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction($type, array($element, $options));
+ }
+
+ /**
+ * Visual Effect: Gradually make the element appear.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function appear($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Appear', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Blind down.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindDown($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.BlindDown', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Blind up.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindUp($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.BlindUp', $element, $options);
+
+ }
+
+ /**
+ * Visual Effect: Drop out.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function dropOut($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.DropOut', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually fade the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fade($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Fade', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Fold.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fold($element, $options = null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Fold', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually make an element grow to a predetermined size.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function grow($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Grow', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually grow and fade the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function puff($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Puff', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Pulsate.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function pulsate($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Pulsate', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Shake the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shake($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Shake', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Shrink the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shrink($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Shrink', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Slide down.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideDown($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SlideDown', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Side up.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideUp($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SlideUp', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Squish the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function squish($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Squish', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Switch Off effect.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function switchOff($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SwitchOff', $element, $options);
+ }
+
+ /**
+ * Visual Effect: High light the element for about 2 seconds.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function highlight($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Prado.Effect.Highlight', $element, $options);
+ }
+
+ /**
+ * Set the opacity on a html element or control.
+ * @param TControl control element or element id
+ * @param float opacity value between 1 and 0
+ */
+ public function setOpacity($element, $value)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $value = TPropertyValue::ensureFloat($value);
+ $this->callClientFunction('Element.setOpacity', array($element,$value));
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSide.php b/framework/Web/UI/ActiveControls/TCallbackClientSide.php
index 10231a1c..0d602fa5 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientSide.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientSide.php
@@ -1,322 +1,322 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientSide class.
- *
- * The following client side events are executing in order if the callback
- * request and response are send and received successfuly.
- *
- * - onPreDispatch executed before a request is dispatched.
- * - onUninitialized executed when callback request is uninitialized.
- * - onLoading * executed when callback request is initiated
- * - onLoaded * executed when callback request begins.
- * - onInteractive executed when callback request is in progress.
- * - onComplete executed when callback response returns.
- * - onSuccess executed when callback request returns and is successful.
- * - onFailure executed when callback request returns and fails.
- * - onException 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.
- *
- * - PostState true to collect the form inputs and post them during callback, default is true.
- * - RequestTimeOut The request timeout in milliseconds.
- * - HasPriority 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.
- * - EnablePageStateUpdate enable the callback response to enable the
- * viewstate update. This will automatically set HasPriority to true when enabled.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientSide extends TClientSideOptions
-{
- /**
- * Returns javascript statement enclosed within a javascript function.
- * @param string javascript statement
- * @return string javascript statement wrapped in a javascript function
- */
- protected function ensureFunction($javascript)
- {
- return "function(sender, parameter){ {$javascript} }";
- }
-
- /**
- * @param string javascript code to be executed before a request is dispatched.
- */
- public function setOnPreDispatch($javascript)
- {
- $this->setFunction('onPreDispatch', $javascript);
- }
-
- /**
- * @return string javascript code to be executed before a request is dispatched.
- */
- public function getOnPreDispatch()
- {
- return $this->getOption('onPreDispatch');
- }
-
- /**
- * @return string javascript code for client-side onUninitialized event
- */
- public function getOnUninitialized()
- {
- return $this->getOption('onUninitialized');
- }
-
- /**
- * @param string javascript code for client-side onUninitialized event.
- */
- public function setOnUninitialized($javascript)
- {
- $this->setFunction('onUninitialized', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoading event
- */
- public function getOnLoading()
- {
- return $this->getOption('onLoading');
- }
-
- /**
- * @param string javascript code for client-side onLoading event.
- */
- public function setOnLoading($javascript)
- {
- $this->setFunction('onLoading', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoaded event
- */
- public function getOnLoaded()
- {
- return $this->getOption('onLoaded');
- }
-
- /**
- * @param string javascript code for client-side onLoaded event.
- */
- public function setOnLoaded($javascript)
- {
- $this->setFunction('onLoaded', $javascript);
- }
- /**
- * @return string javascript code for client-side onInteractive event
- */
- public function getOnInteractive()
- {
- return $this->getOption('onInteractive');
- }
-
- /**
- * @param string javascript code for client-side onInteractive event.
- */
- public function setOnInteractive($javascript)
- {
- $this->setFunction('onInteractive', $javascript);
- }
- /**
- * @return string javascript code for client-side onComplete event
- */
- public function getOnComplete()
- {
- return $this->getOption('onComplete');
- }
-
- /**
- * @param string javascript code for client-side onComplete event.
- */
- public function setOnComplete($javascript)
- {
- $this->setFunction('onComplete', $javascript);
- }
- /**
- * @return string javascript code for client-side onSuccess event
- */
- public function getOnSuccess()
- {
- return $this->getOption('onSuccess');
- }
-
- /**
- * @param string javascript code for client-side onSuccess event.
- */
- public function setOnSuccess($javascript)
- {
- $this->setFunction('onSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onFailure event
- */
- public function getOnFailure()
- {
- return $this->getOption('onFailure');
- }
-
- /**
- * @param string javascript code for client-side onFailure event.
- */
- public function setOnFailure($javascript)
- {
- $this->setFunction('onFailure', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onException event
- */
- public function getOnException()
- {
- return $this->getOption('onException');
- }
-
- /**
- * @param string javascript code for client-side onException event.
- */
- public function setOnException($javascript)
- {
- $this->setFunction('onException', $javascript);
- }
-
- /**
- * @return boolean true to post the inputs of the form on callback, default
- * is post the inputs on callback.
- */
- public function getPostState()
- {
- return $this->getOption('PostInputs');
- }
-
- /**
- * @param boolean true to post the inputs of the form with callback
- * requests. Default is to post the inputs.
- */
- public function setPostState($value)
- {
- $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return integer callback request timeout.
- */
- public function getRequestTimeOut()
- {
- return $this->getOption('RequestTimeOut');
- }
-
- /**
- * @param integer callback request timeout
- */
- public function setRequestTimeOut($value)
- {
- $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
- }
-
- /**
- * @return boolean true if the callback request has priority and will abort
- * existing prioritized request in order to send immediately. It does not
- * affect callbacks that are not prioritized. Default is true.
- */
- public function getHasPriority()
- {
- $option = $this->getOption('HasPriority');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @param boolean true to ensure that the callback request will be sent
- * immediately and will abort existing prioritized requests. It does not
- * affect callbacks that are not prioritized.
- */
- public function setHasPriority($value)
- {
- $hasPriority = TPropertyValue::ensureBoolean($value);
- $this->setOption('HasPriority', $hasPriority);
- if(!$hasPriority)
- $this->setEnablePageStateUpdate(false);
- }
-
- /**
- * Set to true to enable the callback response to enable the viewstate
- * update. This will automatically set HasPrority to true.
- * @param boolean true enables the callback response to update the
- * viewstate.
- */
- public function setEnablePageStateUpdate($value)
- {
- $enabled = TPropertyValue::ensureBoolean($value);
- $this->setOption('EnablePageStateUpdate', $enabled);
- if($enabled)
- $this->setHasPriority(true);
- }
-
- /**
- * @return boolean client-side viewstate will be updated on callback
- * response if true. Default is true.
- */
- public function getEnablePageStateUpdate()
- {
- $option = $this->getOption('EnablePageStateUpdate');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @return string post back target ID
- */
- public function getPostBackTarget()
- {
- return $this->getOption('EventTarget');
- }
-
- /**
- * @param string post back target ID
- */
- public function setPostBackTarget($value)
- {
- if($value instanceof TControl)
- $value = $value->getUniqueID();
- $this->setOption('EventTarget', $value);
- }
-
- /**
- * @return string post back event parameter.
- */
- public function getPostBackParameter()
- {
- return $this->getOption('EventParameter');
- }
-
- /**
- * @param string post back event parameter.
- */
- public function setPostBackParameter($value)
- {
- $this->setOption('EventParameter', $value);
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientSide class.
+ *
+ * The following client side events are executing in order if the callback
+ * request and response are send and received successfuly.
+ *
+ * - onPreDispatch executed before a request is dispatched.
+ * - onUninitialized executed when callback request is uninitialized.
+ * - onLoading * executed when callback request is initiated
+ * - onLoaded * executed when callback request begins.
+ * - onInteractive executed when callback request is in progress.
+ * - onComplete executed when callback response returns.
+ * - onSuccess executed when callback request returns and is successful.
+ * - onFailure executed when callback request returns and fails.
+ * - onException 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.
+ *
+ * - PostState true to collect the form inputs and post them during callback, default is true.
+ * - RequestTimeOut The request timeout in milliseconds.
+ * - HasPriority 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.
+ * - EnablePageStateUpdate enable the callback response to enable the
+ * viewstate update. This will automatically set HasPriority to true when enabled.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientSide extends TClientSideOptions
+{
+ /**
+ * Returns javascript statement enclosed within a javascript function.
+ * @param string javascript statement
+ * @return string javascript statement wrapped in a javascript function
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(sender, parameter){ {$javascript} }";
+ }
+
+ /**
+ * @param string javascript code to be executed before a request is dispatched.
+ */
+ public function setOnPreDispatch($javascript)
+ {
+ $this->setFunction('onPreDispatch', $javascript);
+ }
+
+ /**
+ * @return string javascript code to be executed before a request is dispatched.
+ */
+ public function getOnPreDispatch()
+ {
+ return $this->getOption('onPreDispatch');
+ }
+
+ /**
+ * @return string javascript code for client-side onUninitialized event
+ */
+ public function getOnUninitialized()
+ {
+ return $this->getOption('onUninitialized');
+ }
+
+ /**
+ * @param string javascript code for client-side onUninitialized event.
+ */
+ public function setOnUninitialized($javascript)
+ {
+ $this->setFunction('onUninitialized', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoading event
+ */
+ public function getOnLoading()
+ {
+ return $this->getOption('onLoading');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoading event.
+ */
+ public function setOnLoading($javascript)
+ {
+ $this->setFunction('onLoading', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoaded event
+ */
+ public function getOnLoaded()
+ {
+ return $this->getOption('onLoaded');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoaded event.
+ */
+ public function setOnLoaded($javascript)
+ {
+ $this->setFunction('onLoaded', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onInteractive event
+ */
+ public function getOnInteractive()
+ {
+ return $this->getOption('onInteractive');
+ }
+
+ /**
+ * @param string javascript code for client-side onInteractive event.
+ */
+ public function setOnInteractive($javascript)
+ {
+ $this->setFunction('onInteractive', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onComplete event
+ */
+ public function getOnComplete()
+ {
+ return $this->getOption('onComplete');
+ }
+
+ /**
+ * @param string javascript code for client-side onComplete event.
+ */
+ public function setOnComplete($javascript)
+ {
+ $this->setFunction('onComplete', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onSuccess event
+ */
+ public function getOnSuccess()
+ {
+ return $this->getOption('onSuccess');
+ }
+
+ /**
+ * @param string javascript code for client-side onSuccess event.
+ */
+ public function setOnSuccess($javascript)
+ {
+ $this->setFunction('onSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onFailure event
+ */
+ public function getOnFailure()
+ {
+ return $this->getOption('onFailure');
+ }
+
+ /**
+ * @param string javascript code for client-side onFailure event.
+ */
+ public function setOnFailure($javascript)
+ {
+ $this->setFunction('onFailure', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onException event
+ */
+ public function getOnException()
+ {
+ return $this->getOption('onException');
+ }
+
+ /**
+ * @param string javascript code for client-side onException event.
+ */
+ public function setOnException($javascript)
+ {
+ $this->setFunction('onException', $javascript);
+ }
+
+ /**
+ * @return boolean true to post the inputs of the form on callback, default
+ * is post the inputs on callback.
+ */
+ public function getPostState()
+ {
+ return $this->getOption('PostInputs');
+ }
+
+ /**
+ * @param boolean true to post the inputs of the form with callback
+ * requests. Default is to post the inputs.
+ */
+ public function setPostState($value)
+ {
+ $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return integer callback request timeout.
+ */
+ public function getRequestTimeOut()
+ {
+ return $this->getOption('RequestTimeOut');
+ }
+
+ /**
+ * @param integer callback request timeout
+ */
+ public function setRequestTimeOut($value)
+ {
+ $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * @return boolean true if the callback request has priority and will abort
+ * existing prioritized request in order to send immediately. It does not
+ * affect callbacks that are not prioritized. Default is true.
+ */
+ public function getHasPriority()
+ {
+ $option = $this->getOption('HasPriority');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @param boolean true to ensure that the callback request will be sent
+ * immediately and will abort existing prioritized requests. It does not
+ * affect callbacks that are not prioritized.
+ */
+ public function setHasPriority($value)
+ {
+ $hasPriority = TPropertyValue::ensureBoolean($value);
+ $this->setOption('HasPriority', $hasPriority);
+ if(!$hasPriority)
+ $this->setEnablePageStateUpdate(false);
+ }
+
+ /**
+ * Set to true to enable the callback response to enable the viewstate
+ * update. This will automatically set HasPrority to true.
+ * @param boolean true enables the callback response to update the
+ * viewstate.
+ */
+ public function setEnablePageStateUpdate($value)
+ {
+ $enabled = TPropertyValue::ensureBoolean($value);
+ $this->setOption('EnablePageStateUpdate', $enabled);
+ if($enabled)
+ $this->setHasPriority(true);
+ }
+
+ /**
+ * @return boolean client-side viewstate will be updated on callback
+ * response if true. Default is true.
+ */
+ public function getEnablePageStateUpdate()
+ {
+ $option = $this->getOption('EnablePageStateUpdate');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @return string post back target ID
+ */
+ public function getPostBackTarget()
+ {
+ return $this->getOption('EventTarget');
+ }
+
+ /**
+ * @param string post back target ID
+ */
+ public function setPostBackTarget($value)
+ {
+ if($value instanceof TControl)
+ $value = $value->getUniqueID();
+ $this->setOption('EventTarget', $value);
+ }
+
+ /**
+ * @return string post back event parameter.
+ */
+ public function getPostBackParameter()
+ {
+ return $this->getOption('EventParameter');
+ }
+
+ /**
+ * @param string post back event parameter.
+ */
+ public function setPostBackParameter($value)
+ {
+ $this->setOption('EventParameter', $value);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
index d4038fb5..7c532588 100644
--- a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
+++ b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
@@ -1,87 +1,87 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackEventParameter class.
- *
- * The TCallbackEventParameter provides the parameter passed during the callback
- * request in the {@link getCallbackParameter CallbackParameter} property. The
- * callback response content (e.g. new HTML content) must be rendered
- * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
- * property, which returns a NEW 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
- * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackEventParameter extends TEventParameter
-{
- /**
- * @var THttpResponse output content.
- */
- private $_response;
- /**
- * @var mixed callback request parameter.
- */
- private $_parameter;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter)
- {
- $this->_response = $response;
- $this->_parameter = $parameter;
- }
-
- /**
- * @return TCallbackResponseWriter holds the response content.
- */
- public function getNewWriter()
- {
- return $this->_response->createHtmlWriter(null);
- }
-
- /**
- * @return mixed callback request parameter.
- */
- public function getCallbackParameter()
- {
- return $this->_parameter;
- }
-
- /**
- * @param mixed callback response data.
- */
- public function setResponseData($value)
- {
- $this->_response->getAdapter()->setResponseData($value);
- }
-
- /**
- * @return mixed callback response data.
- */
- public function getResponseData()
- {
- return $this->_response->getAdapter()->getResponseData();
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackEventParameter class.
+ *
+ * The TCallbackEventParameter provides the parameter passed during the callback
+ * request in the {@link getCallbackParameter CallbackParameter} property. The
+ * callback response content (e.g. new HTML content) must be rendered
+ * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
+ * property, which returns a NEW 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
+ * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackEventParameter extends TEventParameter
+{
+ /**
+ * @var THttpResponse output content.
+ */
+ private $_response;
+ /**
+ * @var mixed callback request parameter.
+ */
+ private $_parameter;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter)
+ {
+ $this->_response = $response;
+ $this->_parameter = $parameter;
+ }
+
+ /**
+ * @return TCallbackResponseWriter holds the response content.
+ */
+ public function getNewWriter()
+ {
+ return $this->_response->createHtmlWriter(null);
+ }
+
+ /**
+ * @return mixed callback request parameter.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->_parameter;
+ }
+
+ /**
+ * @param mixed callback response data.
+ */
+ public function setResponseData($value)
+ {
+ $this->_response->getAdapter()->setResponseData($value);
+ }
+
+ /**
+ * @return mixed callback response data.
+ */
+ public function getResponseData()
+ {
+ return $this->_response->getAdapter()->getResponseData();
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackOptions.php b/framework/Web/UI/ActiveControls/TCallbackOptions.php
index baba32e1..e75c2fde 100644
--- a/framework/Web/UI/ActiveControls/TCallbackOptions.php
+++ b/framework/Web/UI/ActiveControls/TCallbackOptions.php
@@ -1,53 +1,53 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackOptions class.
- *
- * TCallbackOptions allows common set of callback client-side options
- * to be attached to other active controls.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackOptions extends TControl
-{
- /**
- * @var TCallbackClientSide client side callback options.
- */
- private $_clientSide;
-
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g.
- * 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');
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackOptions class.
+ *
+ * TCallbackOptions allows common set of callback client-side options
+ * to be attached to other active controls.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackOptions extends TControl
+{
+ /**
+ * @var TCallbackClientSide client side callback options.
+ */
+ private $_clientSide;
+
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g.
+ * See {@link TCallbackClientSide} for details on the properties of
+ * ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide');
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
index c28b435c..38aaabec 100644
--- a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
@@ -1,95 +1,95 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TEventTriggeredCallback Class
- *
- * Triggers a new callback request when a particular {@link setEventName EventName}
- * on a control with ID given by {@link setControlID ControlID} is raised.
- *
- * The default action of the event on the client-side can be prevented when
- * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TEventTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The client-side event name the trigger listens to.
- */
- public function getEventName()
- {
- return $this->getViewState('EventName', '');
- }
-
- /**
- * Sets the client-side event name that fires the callback request.
- * @param string The client-side event name the trigger listens to.
- */
- public function setEventName($value)
- {
- $this->setViewState('EventName', $value, '');
- }
-
- /**
- * @param boolean true to prevent/stop default event action.
- */
- public function setPreventDefaultAction($value)
- {
- $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
- }
-
- /**
- * @return boolean true to prevent/stop default event action.
- */
- public function getPreventDefaultAction()
- {
- return $this->getViewState('StopEvent', false);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $name = preg_replace('/^on/', '', $this->getEventName());
- $options['EventName'] = strtolower($name);
- $options['StopEvent'] = $this->getPreventDefaultAction();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEventTriggeredCallback';
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TEventTriggeredCallback Class
+ *
+ * Triggers a new callback request when a particular {@link setEventName EventName}
+ * on a control with ID given by {@link setControlID ControlID} is raised.
+ *
+ * The default action of the event on the client-side can be prevented when
+ * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TEventTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The client-side event name the trigger listens to.
+ */
+ public function getEventName()
+ {
+ return $this->getViewState('EventName', '');
+ }
+
+ /**
+ * Sets the client-side event name that fires the callback request.
+ * @param string The client-side event name the trigger listens to.
+ */
+ public function setEventName($value)
+ {
+ $this->setViewState('EventName', $value, '');
+ }
+
+ /**
+ * @param boolean true to prevent/stop default event action.
+ */
+ public function setPreventDefaultAction($value)
+ {
+ $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return boolean true to prevent/stop default event action.
+ */
+ public function getPreventDefaultAction()
+ {
+ return $this->getViewState('StopEvent', false);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $name = preg_replace('/^on/', '', $this->getEventName());
+ $options['EventName'] = strtolower($name);
+ $options['StopEvent'] = $this->getPreventDefaultAction();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEventTriggeredCallback';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
index aba477b9..47c8aeac 100644
--- a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
+++ b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
@@ -1,290 +1,290 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-
-/**
- * TInPlaceTextBox Class
- * *
- * TInPlaceTextBox is a component rendered as a label and allows its
- * contents to be edited by changing the label to a textbox when
- * the label is clicked or when another control or html element with
- * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
- *
- * If the {@link OnLoadingText} event is handled, a callback request is
- * made when the label is clicked, while the request is being made the
- * textbox is disabled from editing. The {@link OnLoadingText} event allows
- * you to update the content of the textbox before the client is allowed
- * to edit the content. After the callback request returns successfully,
- * the textbox is enabled and the contents is then allowed to be edited.
- *
- * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
- * is true and the textbox content has changed, a callback request is made and
- * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
- * During the request, the textbox is disabled.
- *
- * After the callback request returns sucessfully, the textbox is enabled.
- * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
- * the textbox will be hidden and the label is then shown.
- *
- * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
- * the control not editable. This property can be also changed on callback
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInPlaceTextBox extends TActiveTextBox
-{
- /**
- * Sets the auto post back to true by default.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAutoPostBack(true);
- }
-
- /**
- * @param boolean true to hide the textbox after losing focus.
- */
- public function setAutoHideTextBox($value)
- {
- $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true will hide the textbox after losing focus.
- */
- public function getAutoHideTextBox()
- {
- return $this->getViewState('AutoHide', true);
- }
-
- /**
- * @param boolean true to display the edit textbox
- */
- public function setDisplayTextBox($value)
- {
- $value = TPropertyValue::ensureBoolean($value);
- $this->setViewState('DisplayTextBox', $value,false);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->callClientFunction('setDisplayTextBox',$value);
- }
-
- /**
- * @return boolean true to display the edit textbox
- */
- public function getDisplayTextBox()
- {
- return $this->getViewState('DisplayTextBox', false);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- $client = $this->getPage()->getCallbackClient();
- $code = $this->getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
-
- /**
- * @param string ID of the control that can trigger to edit the textbox
- */
- public function setEditTriggerControlID($value)
- {
- $this->setViewState('EditTriggerControlID', $value);
- }
-
- /**
- * @return string ID of the control that can trigger to edit the textbox
- */
- public function getEditTriggerControlID()
- {
- return $this->getViewState('EditTriggerControlID');
- }
-
- /**
- * @return string edit trigger control client ID.
- */
- protected function getExternalControlID()
- {
- $extID = $this->getEditTriggerControlID();
- if($extID===null) return '';
- if(($control = $this->findControl($extID))!==null)
- return $control->getClientID();
- return $extID;
- }
-
- /**
- * On callback response, the inner HTMl of the label and the
- * value of the textbox is updated
- * @param string the text value of the label
- */
- public function setText($value)
- {
- TTextBox::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $client->update($this->getLabelClientID(), $value);
- $client->setValue($this, $value);
- }
- }
-
- /**
- * Update ClientSide Readonly property
- * @param boolean value
- * @since 3.1.2
- */
- public function setReadOnly ($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- TTextBox::setReadOnly($value);
- if ($this->getActiveControl()->canUpdateClientSide())
- {
- $this->callClientFunction('setReadOnly', $value);
- }
- }
-
- /**
- * @return string tag name of the label.
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Renders the body content of the label.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string label client ID
- */
- protected function getLabelClientID()
- {
- return $this->getClientID().'__label';
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $action = $param->getCallbackParameter();
- if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
- {
- $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
- $this->onLoadingText($parameter);
- }
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @return array callback options.
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['ID'] = $this->getLabelClientID();
- $options['TextBoxID'] = $this->getClientID();
- $options['ExternalControl'] = $this->getExternalControlID();
- $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
- $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
- $options['Columns'] = $this->getColumns();
- if($this->getTextMode()==='MultiLine')
- {
- $options['Rows'] = $this->getRows();
- $options['Wrap'] = $this->getWrap()== false ? '' : true;
- }
- else
- {
- $length = $this->getMaxLength();
- $options['MaxLength'] = $length > 0 ? $length : '';
- }
-
- if($this->hasEventHandler('OnLoadingText'))
- $options['LoadTextOnEdit'] = true;
-
- $options['ReadOnly']=$this->getReadOnly();
- return $options;
- }
-
- /**
- * Raised when editing the content is requsted to be loaded from the
- * server side.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onLoadingText($param)
- {
- $this->raiseEvent('OnLoadingText',$this,$param);
- }
-
- /**
- * @return string corresponding javascript class name for this TInPlaceTextBox
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TInPlaceTextBox';
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
- TWebControl::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getLabelClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->registerClientScript();
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('inlineeditor');
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+
+/**
+ * TInPlaceTextBox Class
+ * *
+ * TInPlaceTextBox is a component rendered as a label and allows its
+ * contents to be edited by changing the label to a textbox when
+ * the label is clicked or when another control or html element with
+ * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
+ *
+ * If the {@link OnLoadingText} event is handled, a callback request is
+ * made when the label is clicked, while the request is being made the
+ * textbox is disabled from editing. The {@link OnLoadingText} event allows
+ * you to update the content of the textbox before the client is allowed
+ * to edit the content. After the callback request returns successfully,
+ * the textbox is enabled and the contents is then allowed to be edited.
+ *
+ * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
+ * is true and the textbox content has changed, a callback request is made and
+ * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
+ * During the request, the textbox is disabled.
+ *
+ * After the callback request returns sucessfully, the textbox is enabled.
+ * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
+ * the textbox will be hidden and the label is then shown.
+ *
+ * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
+ * the control not editable. This property can be also changed on callback
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInPlaceTextBox extends TActiveTextBox
+{
+ /**
+ * Sets the auto post back to true by default.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @param boolean true to hide the textbox after losing focus.
+ */
+ public function setAutoHideTextBox($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true will hide the textbox after losing focus.
+ */
+ public function getAutoHideTextBox()
+ {
+ return $this->getViewState('AutoHide', true);
+ }
+
+ /**
+ * @param boolean true to display the edit textbox
+ */
+ public function setDisplayTextBox($value)
+ {
+ $value = TPropertyValue::ensureBoolean($value);
+ $this->setViewState('DisplayTextBox', $value,false);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->callClientFunction('setDisplayTextBox',$value);
+ }
+
+ /**
+ * @return boolean true to display the edit textbox
+ */
+ public function getDisplayTextBox()
+ {
+ return $this->getViewState('DisplayTextBox', false);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = $this->getClientClassName().'.'.$func;
+ $client->callClientFunction($code,array($this,$value));
+ }
+
+ /**
+ * @param string ID of the control that can trigger to edit the textbox
+ */
+ public function setEditTriggerControlID($value)
+ {
+ $this->setViewState('EditTriggerControlID', $value);
+ }
+
+ /**
+ * @return string ID of the control that can trigger to edit the textbox
+ */
+ public function getEditTriggerControlID()
+ {
+ return $this->getViewState('EditTriggerControlID');
+ }
+
+ /**
+ * @return string edit trigger control client ID.
+ */
+ protected function getExternalControlID()
+ {
+ $extID = $this->getEditTriggerControlID();
+ if($extID===null) return '';
+ if(($control = $this->findControl($extID))!==null)
+ return $control->getClientID();
+ return $extID;
+ }
+
+ /**
+ * On callback response, the inner HTMl of the label and the
+ * value of the textbox is updated
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ TTextBox::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->update($this->getLabelClientID(), $value);
+ $client->setValue($this, $value);
+ }
+ }
+
+ /**
+ * Update ClientSide Readonly property
+ * @param boolean value
+ * @since 3.1.2
+ */
+ public function setReadOnly ($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ TTextBox::setReadOnly($value);
+ if ($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->callClientFunction('setReadOnly', $value);
+ }
+ }
+
+ /**
+ * @return string tag name of the label.
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string label client ID
+ */
+ protected function getLabelClientID()
+ {
+ return $this->getClientID().'__label';
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $action = $param->getCallbackParameter();
+ if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
+ {
+ $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
+ $this->onLoadingText($parameter);
+ }
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @return array callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['ID'] = $this->getLabelClientID();
+ $options['TextBoxID'] = $this->getClientID();
+ $options['ExternalControl'] = $this->getExternalControlID();
+ $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
+ $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
+ $options['Columns'] = $this->getColumns();
+ if($this->getTextMode()==='MultiLine')
+ {
+ $options['Rows'] = $this->getRows();
+ $options['Wrap'] = $this->getWrap()== false ? '' : true;
+ }
+ else
+ {
+ $length = $this->getMaxLength();
+ $options['MaxLength'] = $length > 0 ? $length : '';
+ }
+
+ if($this->hasEventHandler('OnLoadingText'))
+ $options['LoadTextOnEdit'] = true;
+
+ $options['ReadOnly']=$this->getReadOnly();
+ return $options;
+ }
+
+ /**
+ * Raised when editing the content is requsted to be loaded from the
+ * server side.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoadingText($param)
+ {
+ $this->raiseEvent('OnLoadingText',$this,$param);
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TInPlaceTextBox
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TInPlaceTextBox';
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
+ TWebControl::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getLabelClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->registerClientScript();
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('inlineeditor');
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
index fd1fabb1..4b89cb8e 100644
--- a/framework/Web/UI/ActiveControls/TTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
@@ -1,71 +1,71 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallback');
-/**
- * TTriggeredCallback abstract Class
- *
- * Base class for triggered callback controls. The {@link setControlID ControlID}
- * property sets the control ID to observe the trigger.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TTriggeredCallback extends TCallback
-{
- /**
- * @return string The ID of the server control the trigger is bounded to.
- */
- public function getControlID()
- {
- return $this->getViewState('ControlID', '');
- }
-
- /**
- * @param string The ID of the server control the trigger is bounded to.
- */
- public function setControlID($value)
- {
- $this->setViewState('ControlID', $value, '');
- }
-
- /**
- * @return string target control client ID or html element ID if
- * control is not found in hierarchy.
- */
- protected function getTargetControl()
- {
- $id = $this->getControlID();
- if(($control=$this->findControl($id)) instanceof TControl)
- return $control->getClientID();
- if($id==='')
- {
- throw new TConfigurationException(
- 'ttriggeredcallback_invalid_controlid', get_class($this));
- }
- return $id;
- }
-
- /**
- * @return array list of trigger callback options.
- */
- protected function getTriggerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['ControlID'] = $this->getTargetControl();
- return $options;
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallback');
+/**
+ * TTriggeredCallback abstract Class
+ *
+ * Base class for triggered callback controls. The {@link setControlID ControlID}
+ * property sets the control ID to observe the trigger.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TTriggeredCallback extends TCallback
+{
+ /**
+ * @return string The ID of the server control the trigger is bounded to.
+ */
+ public function getControlID()
+ {
+ return $this->getViewState('ControlID', '');
+ }
+
+ /**
+ * @param string The ID of the server control the trigger is bounded to.
+ */
+ public function setControlID($value)
+ {
+ $this->setViewState('ControlID', $value, '');
+ }
+
+ /**
+ * @return string target control client ID or html element ID if
+ * control is not found in hierarchy.
+ */
+ protected function getTargetControl()
+ {
+ $id = $this->getControlID();
+ if(($control=$this->findControl($id)) instanceof TControl)
+ return $control->getClientID();
+ if($id==='')
+ {
+ throw new TConfigurationException(
+ 'ttriggeredcallback_invalid_controlid', get_class($this));
+ }
+ return $id;
+ }
+
+ /**
+ * @return array list of trigger callback options.
+ */
+ protected function getTriggerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ControlID'] = $this->getTargetControl();
+ return $options;
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
index 58a78d08..899419ee 100644
--- a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
@@ -1,120 +1,120 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TValueTriggeredCallback Class
- *
- * Observes the value with {@link setPropertyName PropertyName} of a
- * control with {@link setControlID ControlID}. Changes to the observed
- * property value will trigger a new callback request. The property value is checked
- * for changes every{@link setInterval Interval} seconds.
- *
- * A {@link setDecayRate DecayRate} can be set to increase the polling
- * interval linearly if no changes are observed. Once a change is
- * observed, the polling interval is reset to the original value.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TValueTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The control property name to observe value changes.
- */
- public function getPropertyName()
- {
- return $this->getViewState('PropertyName', '');
- }
-
- /**
- * Sets the control property name to observe value changes that fires the callback request.
- * @param string The control property name to observe value changes.
- */
- public function setPropertyName($value)
- {
- $this->setViewState('PropertyName', $value, '');
- }
-
- /**
- * Sets the polling interval in seconds to observe property changes.
- * Default is 1 second.
- * @param float polling interval in seconds.
- */
- public function setInterval($value)
- {
- $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
- }
-
- /**
- * @return float polling interval, 1 second default.
- */
- public function getInterval()
- {
- return $this->getViewState('Interval', 1);
- }
-
- /**
- * Gets the decay rate between callbacks. Default is 0;
- * @return float decay rate between callbacks.
- */
- public function getDecayRate()
- {
- return $this->getViewState('Decay', 0);
- }
-
- /**
- * Sets the decay rate between callback. Default is 0;
- * @param float decay rate between callbacks.
- */
- public function setDecayRate($value)
- {
- $decay = TPropertyValue::ensureFloat($value);
- if($decay < 0)
- throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
- $this->setViewState('Decay', $decay);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $options['PropertyName'] = $this->getPropertyName();
- $options['Interval'] = $this->getInterval();
- $options['Decay'] = $this->getDecayRate();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TValueTriggeredCallback';
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TValueTriggeredCallback Class
+ *
+ * Observes the value with {@link setPropertyName PropertyName} of a
+ * control with {@link setControlID ControlID}. Changes to the observed
+ * property value will trigger a new callback request. The property value is checked
+ * for changes every{@link setInterval Interval} seconds.
+ *
+ * A {@link setDecayRate DecayRate} can be set to increase the polling
+ * interval linearly if no changes are observed. Once a change is
+ * observed, the polling interval is reset to the original value.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TValueTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The control property name to observe value changes.
+ */
+ public function getPropertyName()
+ {
+ return $this->getViewState('PropertyName', '');
+ }
+
+ /**
+ * Sets the control property name to observe value changes that fires the callback request.
+ * @param string The control property name to observe value changes.
+ */
+ public function setPropertyName($value)
+ {
+ $this->setViewState('PropertyName', $value, '');
+ }
+
+ /**
+ * Sets the polling interval in seconds to observe property changes.
+ * Default is 1 second.
+ * @param float polling interval in seconds.
+ */
+ public function setInterval($value)
+ {
+ $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
+ }
+
+ /**
+ * @return float polling interval, 1 second default.
+ */
+ public function getInterval()
+ {
+ return $this->getViewState('Interval', 1);
+ }
+
+ /**
+ * Gets the decay rate between callbacks. Default is 0;
+ * @return float decay rate between callbacks.
+ */
+ public function getDecayRate()
+ {
+ return $this->getViewState('Decay', 0);
+ }
+
+ /**
+ * Sets the decay rate between callback. Default is 0;
+ * @param float decay rate between callbacks.
+ */
+ public function setDecayRate($value)
+ {
+ $decay = TPropertyValue::ensureFloat($value);
+ if($decay < 0)
+ throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
+ $this->setViewState('Decay', $decay);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $options['PropertyName'] = $this->getPropertyName();
+ $options['Interval'] = $this->getInterval();
+ $options['Decay'] = $this->getDecayRate();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TValueTriggeredCallback';
+ }
+}
diff --git a/framework/Web/UI/TCachePageStatePersister.php b/framework/Web/UI/TCachePageStatePersister.php
index 486c87ca..34b9203a 100644
--- a/framework/Web/UI/TCachePageStatePersister.php
+++ b/framework/Web/UI/TCachePageStatePersister.php
@@ -1,200 +1,200 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCachePageStatePersister class
- *
- * TCachePageStatePersister implements a page state persistent method based on cache.
- * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
- * is passed to the client side to identify the state. This greatly reduces the size of
- * the page state that needs to be transmitted between the server and the client. Of course,
- * this is at the cost of using server side resource.
- *
- * A cache module has to be loaded in order to use TCachePageStatePersister.
- * By default, TCachePageStatePersister will use the primary cache module.
- * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
- * Any cache module, as long as it implements the interface {@link ICache}, may be used.
- * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
- *
- * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
- * that stores in cache.
- *
- * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
- * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
- *
- * There are a couple of ways to use TCachePageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TCachePageStatePersister instance there.
- * Or one can configure the pages to use TCachePageStatePersister in page configurations
- * as follows,
- *
- *
- *
- * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
- * for the TCachePageStatePersister instance.
- *
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TCachePageStatePersister, use
- *
- *
- *
- *
- *
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1.1
- */
-class TCachePageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_prefix='statepersister';
- private $_page;
- private $_cache=null;
- private $_cacheModuleID='';
- private $_timeout=1800;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return string the ID of the cache module.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If not set, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * @return ICache the cache module being used for data storage
- */
- public function getCache()
- {
- if($this->_cache===null)
- {
- if($this->_cacheModuleID!=='')
- $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
- else
- $cache=Prado::getApplication()->getCache();
- if($cache===null || !($cache instanceof ICache))
- {
- if($this->_cacheModuleID!=='')
- throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
- else
- throw new TConfigurationException('cachepagestatepersister_cache_required');
- }
- $this->_cache=$cache;
- }
- return $this->_cache;
- }
-
- /**
- * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
- */
- public function getCacheTimeout()
- {
- return $this->_timeout;
- }
-
- /**
- * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
- * @throws TInvalidDataValueException if the number is smaller than 0.
- */
- public function setCacheTimeout($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>=0)
- $this->_timeout=$value;
- else
- throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
- }
-
- /**
- * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
- */
- public function getKeyPrefix()
- {
- return $this->_prefix;
- }
-
- /**
- * @param string prefix of cache variable name to avoid conflict with other cache data
- */
- public function setKeyPrefix($value)
- {
- $this->_prefix=$value;
- }
-
- /**
- * @param string micro timestamp when saving state occurs
- * @return string a key that is unique per user request
- */
- protected function calculateKey($timestamp)
- {
- return $this->getKeyPrefix().':'
- . $this->_page->getRequest()->getUserHostAddress()
- . $this->_page->getPagePath()
- . $timestamp;
- }
-
- /**
- * Saves state in cache.
- * @param mixed state to be stored
- */
- public function save($data)
- {
- $timestamp=(string)microtime(true);
- $key=$this->calculateKey($timestamp);
- $this->getCache()->add($key,$data,$this->_timeout);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from cache.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $key=$this->calculateKey($timestamp);
- if(($data=$this->getCache()->get($key))!==false)
- return $data;
- }
- throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TCachePageStatePersister class
+ *
+ * TCachePageStatePersister implements a page state persistent method based on cache.
+ * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
+ * is passed to the client side to identify the state. This greatly reduces the size of
+ * the page state that needs to be transmitted between the server and the client. Of course,
+ * this is at the cost of using server side resource.
+ *
+ * A cache module has to be loaded in order to use TCachePageStatePersister.
+ * By default, TCachePageStatePersister will use the primary cache module.
+ * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
+ * Any cache module, as long as it implements the interface {@link ICache}, may be used.
+ * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
+ *
+ * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
+ * that stores in cache.
+ *
+ * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
+ * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
+ *
+ * There are a couple of ways to use TCachePageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TCachePageStatePersister instance there.
+ * Or one can configure the pages to use TCachePageStatePersister in page configurations
+ * as follows,
+ *
+ *
+ *
+ * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
+ * for the TCachePageStatePersister instance.
+ *
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TCachePageStatePersister, use
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1.1
+ */
+class TCachePageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_prefix='statepersister';
+ private $_page;
+ private $_cache=null;
+ private $_cacheModuleID='';
+ private $_timeout=1800;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return string the ID of the cache module.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If not set, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * @return ICache the cache module being used for data storage
+ */
+ public function getCache()
+ {
+ if($this->_cache===null)
+ {
+ if($this->_cacheModuleID!=='')
+ $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
+ else
+ $cache=Prado::getApplication()->getCache();
+ if($cache===null || !($cache instanceof ICache))
+ {
+ if($this->_cacheModuleID!=='')
+ throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
+ else
+ throw new TConfigurationException('cachepagestatepersister_cache_required');
+ }
+ $this->_cache=$cache;
+ }
+ return $this->_cache;
+ }
+
+ /**
+ * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
+ */
+ public function getCacheTimeout()
+ {
+ return $this->_timeout;
+ }
+
+ /**
+ * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
+ * @throws TInvalidDataValueException if the number is smaller than 0.
+ */
+ public function setCacheTimeout($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>=0)
+ $this->_timeout=$value;
+ else
+ throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
+ }
+
+ /**
+ * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
+ */
+ public function getKeyPrefix()
+ {
+ return $this->_prefix;
+ }
+
+ /**
+ * @param string prefix of cache variable name to avoid conflict with other cache data
+ */
+ public function setKeyPrefix($value)
+ {
+ $this->_prefix=$value;
+ }
+
+ /**
+ * @param string micro timestamp when saving state occurs
+ * @return string a key that is unique per user request
+ */
+ protected function calculateKey($timestamp)
+ {
+ return $this->getKeyPrefix().':'
+ . $this->_page->getRequest()->getUserHostAddress()
+ . $this->_page->getPagePath()
+ . $timestamp;
+ }
+
+ /**
+ * Saves state in cache.
+ * @param mixed state to be stored
+ */
+ public function save($data)
+ {
+ $timestamp=(string)microtime(true);
+ $key=$this->calculateKey($timestamp);
+ $this->getCache()->add($key,$data,$this->_timeout);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from cache.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $key=$this->calculateKey($timestamp);
+ if(($data=$this->getCache()->get($key))!==false)
+ return $data;
+ }
+ throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TCompositeControl.php b/framework/Web/UI/TCompositeControl.php
index 285a8129..e7766ab8 100644
--- a/framework/Web/UI/TCompositeControl.php
+++ b/framework/Web/UI/TCompositeControl.php
@@ -1,38 +1,38 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCompositeControl class.
- * TCompositeControl is the base class for controls that are composed
- * by other controls.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeControl extends TControl implements INamingContainer
-{
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TCompositeControl class.
+ * TCompositeControl is the base class for controls that are composed
+ * by other controls.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeControl extends TControl implements INamingContainer
+{
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ parent::initRecursive($namingContainer);
+ }
+}
+
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php
index 316098a1..2adabb55 100644
--- a/framework/Web/UI/TControl.php
+++ b/framework/Web/UI/TControl.php
@@ -1,2395 +1,2395 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TAttributeCollection and TControlAdapter class
- */
-Prado::using('System.Collections.TAttributeCollection');
-Prado::using('System.Web.UI.TControlAdapter');
-
-/**
- * TControl class
- *
- * TControl is the base class for all components on a page hierarchy.
- * It implements the following features for UI-related functionalities:
- * - databinding feature
- * - parent and child relationship
- * - naming container and containee relationship
- * - viewstate and controlstate features
- * - rendering scheme
- * - control lifecycles
- *
- * A property can be data-bound with an expression. By calling {@link dataBind},
- * expressions bound to properties will be evaluated and the results will be
- * set to the corresponding properties.
- *
- * Parent and child relationship determines how the presentation of controls are
- * enclosed within each other. A parent will determine where to place
- * the presentation of its child controls. For example, a TPanel will enclose
- * all its child controls' presentation within a div html tag. A control's parent
- * can be obtained via {@link getParent Parent} property, and its
- * {@link getControls Controls} property returns a list of the control's children,
- * including controls and static texts. The property can be manipulated
- * like an array for adding or removing a child (see {@link TList} for more details).
- *
- * A naming container control implements INamingContainer and ensures that
- * its containee controls can be differentiated by their ID property values.
- * Naming container and containee realtionship specifies a protocol to uniquely
- * identify an arbitrary control on a page hierarchy by an ID path (concatenation
- * of all naming containers' IDs and the target control's ID).
- *
- * Viewstate and controlstate are two approaches to preserve state across
- * page postback requests. ViewState is mainly related with UI specific state
- * and can be disabled if not needed. ControlState represents crucial logic state
- * and cannot be disabled.
- *
- * A control is rendered via its {@link render()} method (the method is invoked
- * by the framework.) Descendant control classes may override this method for
- * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
- * which is responsible for rendering of children of the control.
- * Control's {@link getVisible Visible} property governs whether the control
- * should be rendered or not.
- *
- * Each control on a page will undergo a series of lifecycles, including
- * control construction, Init, Load, PreRender, Render, and OnUnload.
- * They work together with page lifecycles to process a page request.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControl extends TApplicationComponent implements IRenderable, IBindable
-{
- /**
- * format of control ID
- */
- const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
- /**
- * separator char between IDs in a UniqueID
- */
- const ID_SEPARATOR='$';
- /**
- * separator char between IDs in a ClientID
- */
- const CLIENT_ID_SEPARATOR='_';
- /**
- * prefix to an ID automatically generated
- */
- const AUTOMATIC_ID_PREFIX='ctl';
-
- /**
- * the stage of lifecycles that the control is currently at
- */
- const CS_CONSTRUCTED=0;
- const CS_CHILD_INITIALIZED=1;
- const CS_INITIALIZED=2;
- const CS_STATE_LOADED=3;
- const CS_LOADED=4;
- const CS_PRERENDERED=5;
-
- /**
- * State bits.
- */
- const IS_ID_SET=0x01;
- const IS_DISABLE_VIEWSTATE=0x02;
- const IS_SKIN_APPLIED=0x04;
- const IS_STYLESHEET_APPLIED=0x08;
- const IS_DISABLE_THEMING=0x10;
- const IS_CHILD_CREATED=0x20;
- const IS_CREATING_CHILD=0x40;
-
- /**
- * Indexes for the rare fields.
- * In order to save memory, rare fields will only be created if they are needed.
- */
- const RF_CONTROLS=0; // child controls
- const RF_CHILD_STATE=1; // child state field
- const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
- const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
- const RF_SKIN_ID=4; // skin ID
- const RF_DATA_BINDINGS=5; // data bindings
- const RF_EVENTS=6; // event handlers
- const RF_CONTROLSTATE=7; // controlstate
- const RF_NAMED_OBJECTS=8; // controls declared with ID on template
- const RF_ADAPTER=9; // adapter
- const RF_AUTO_BINDINGS=10; // auto data bindings
-
- /**
- * @var string control ID
- */
- private $_id='';
- /**
- * @var string control unique ID
- */
- private $_uid;
- /**
- * @var TControl parent of the control
- */
- private $_parent;
- /**
- * @var TPage page that the control resides in
- */
- private $_page;
- /**
- * @var TControl naming container of the control
- */
- private $_namingContainer;
- /**
- * @var TTemplateControl control whose template contains the control
- */
- private $_tplControl;
- /**
- * @var array viewstate data
- */
- private $_viewState=array();
- /**
- * @var array temporary state (usually set in template)
- */
- private $_tempState=array();
- /**
- * @var boolean whether we should keep state in viewstate
- */
- private $_trackViewState=true;
- /**
- * @var integer the current stage of the control lifecycles
- */
- private $_stage=0;
- /**
- * @var integer representation of the state bits
- */
- private $_flags=0;
- /**
- * @var array a collection of rare control data
- */
- private $_rf=array();
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- }
-
- /**
- * Returns a property value by name or a control by ID.
- * This overrides the parent implementation by allowing accessing
- * a control via its ID using the following syntax,
- *
- * $menuBar=$this->menuBar;
- *
- * Note, the control must be configured in the template
- * with explicit ID. If the name matches both a property and a control ID,
- * the control ID will take the precedence.
- *
- * @param string the property name or control ID
- * @return mixed the property value or the target control
- * @throws TInvalidOperationException if the property is not defined.
- * @see registerObject
- */
- public function __get($name)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- return $this->_rf[self::RF_NAMED_OBJECTS][$name];
- else
- return parent::__get($name);
- }
-
- /**
- * @return boolean whether there is an adapter for this control
- */
- public function getHasAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER]);
- }
-
- /**
- * @return TControlAdapter control adapter. Null if not exists.
- */
- public function getAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
- }
-
- /**
- * @param TControlAdapter control adapter
- */
- public function setAdapter(TControlAdapter $adapter)
- {
- $this->_rf[self::RF_ADAPTER]=$adapter;
- }
-
- /**
- * @return TControl the parent of this control
- */
- public function getParent()
- {
- return $this->_parent;
- }
-
- /**
- * @return TControl the naming container of this control
- */
- public function getNamingContainer()
- {
- if(!$this->_namingContainer && $this->_parent)
- {
- if($this->_parent instanceof INamingContainer)
- $this->_namingContainer=$this->_parent;
- else
- $this->_namingContainer=$this->_parent->getNamingContainer();
- }
- return $this->_namingContainer;
- }
-
- /**
- * @return TPage the page that contains this control
- */
- public function getPage()
- {
- if(!$this->_page)
- {
- if($this->_parent)
- $this->_page=$this->_parent->getPage();
- else if($this->_tplControl)
- $this->_page=$this->_tplControl->getPage();
- }
- return $this->_page;
- }
-
- /**
- * Sets the page for a control.
- * Only framework developers should use this method.
- * @param TPage the page that contains this control
- */
- public function setPage($page)
- {
- $this->_page=$page;
- }
-
- /**
- * Sets the control whose template contains this control.
- * Only framework developers should use this method.
- * @param TTemplateControl the control whose template contains this control
- */
- public function setTemplateControl($control)
- {
- $this->_tplControl=$control;
- }
-
- /**
- * @return TTemplateControl the control whose template contains this control
- */
- public function getTemplateControl()
- {
- if(!$this->_tplControl && $this->_parent)
- $this->_tplControl=$this->_parent->getTemplateControl();
- return $this->_tplControl;
- }
-
- /**
- * @return TTemplateControl the control whose template is loaded from
- * some external storage, such as file, db, and whose template ultimately
- * contains this control.
- */
- public function getSourceTemplateControl()
- {
- $control=$this;
- while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
- {
- if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
- return $control;
- }
- return $this->getPage();
- }
-
- /**
- * Gets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @return integer the lifecycle step the control is currently at.
- * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function getControlStage()
- {
- return $this->_stage;
- }
-
- /**
- * Sets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @param integer the lifecycle step the control is currently at.
- * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function setControlStage($value)
- {
- $this->_stage=$value;
- }
-
- /**
- * Returns the id of the control.
- * Control ID can be either manually set or automatically generated.
- * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
- * @param boolean whether to hide automatically generated ID
- * @return string the ID of the control
- */
- public function getID($hideAutoID=true)
- {
- if($hideAutoID)
- return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
- else
- return $this->_id;
- }
-
- /**
- * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
- * @throws TInvalidDataValueException if ID is in a bad format
- */
- public function setID($id)
- {
- if(!preg_match(self::ID_FORMAT,$id))
- throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
- $this->_id=$id;
- $this->_flags |= self::IS_ID_SET;
- $this->clearCachedUniqueID($this instanceof INamingContainer);
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Returns a unique ID that identifies the control in the page hierarchy.
- * A unique ID is the contenation of all naming container controls' IDs and the control ID.
- * These IDs are separated by '$' character.
- * Control users should not rely on the specific format of UniqueID, however.
- * @return string a unique ID that identifies the control in the page hierarchy
- */
- public function getUniqueID()
- {
- if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
- {
- $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
- if($namingContainer=$this->getNamingContainer())
- {
- if($this->getPage()===$namingContainer)
- return ($this->_uid=$this->_id);
- else if(($prefix=$namingContainer->getUniqueID())==='')
- return $this->_id;
- else
- return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
- }
- else // no naming container
- return $this->_id;
- }
- else
- return $this->_uid;
- }
-
- /**
- * Sets input focus to this control.
- */
- public function focus()
- {
- $this->getPage()->setFocus($this);
- }
-
- /**
- * Returns the client ID of the control.
- * The client ID can be used to uniquely identify
- * the control in client-side scripts (such as JavaScript).
- * Do not rely on the explicit format of the return ID.
- * @return string the client ID of the control
- */
- public function getClientID()
- {
- return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * Converts a unique ID to a client ID.
- * @param string the unique ID of a control
- * @return string the client ID of the control
- */
- public static function convertUniqueIdToClientId($uniqueID)
- {
- return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * @return string the skin ID of this control, '' if not set
- */
- public function getSkinID()
- {
- return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function setSkinID($value)
- {
- if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
- else
- $this->_rf[self::RF_SKIN_ID]=$value;
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function getIsSkinApplied()
- {
- return ($this->_flags & self::IS_SKIN_APPLIED);
- }
-
- /**
- * @return boolean whether theming is enabled for this control.
- * The theming is enabled if the control and all its parents have it enabled.
- */
- public function getEnableTheming()
- {
- if($this->_flags & self::IS_DISABLE_THEMING)
- return false;
- else
- return $this->_parent?$this->_parent->getEnableTheming():true;
- }
-
- /**
- * @param boolean whether to enable theming
- * @throws TInvalidOperationException if this method is invoked after OnPreInit
- */
- public function setEnableTheming($value)
- {
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
- else if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_THEMING;
- else
- $this->_flags |= self::IS_DISABLE_THEMING;
- }
-
- /**
- * Returns custom data associated with this control.
- * A control may be associated with some custom data for various purposes.
- * For example, a button may be associated with a string to identify itself
- * in a generic OnClick event handler.
- * @return mixed custom data associated with this control. Defaults to null.
- */
- public function getCustomData()
- {
- return $this->getViewState('CustomData',null);
- }
-
- /**
- * Associates custom data with this control.
- * Note, the custom data must be serializable and unserializable.
- * @param mixed custom data
- */
- public function setCustomData($value)
- {
- $this->setViewState('CustomData',$value,null);
- }
-
- /**
- * @return boolean whether the control has child controls
- */
- public function getHasControls()
- {
- return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
- }
-
- /**
- * @return TControlCollection the child control collection
- */
- public function getControls()
- {
- if(!isset($this->_rf[self::RF_CONTROLS]))
- $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
- return $this->_rf[self::RF_CONTROLS];
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TControlCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
- }
-
- /**
- * Checks if a control is visible.
- * If parent check is required, then a control is visible only if the control
- * and all its ancestors are visible.
- * @param boolean whether the parents should also be checked if visible
- * @return boolean whether the control is visible (default=true).
- */
- public function getVisible($checkParents=true)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getVisible(false))
- return false;
- return true;
- }
- else
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the control is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a value indicating whether the control is enabled.
- * A control is enabled if it allows client user interaction.
- * If $checkParents is true, all parent controls will be checked,
- * and unless they are all enabled, false will be returned.
- * The property Enabled is mainly used for {@link TWebControl}
- * derived controls.
- * @param boolean whether the parents should also be checked enabled
- * @return boolean whether the control is enabled.
- */
- public function getEnabled($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getViewState('Enabled',true))
- return false;
- return true;
- }
- else
- return $this->getViewState('Enabled',true);
- }
-
- /**
- * @param boolean whether the control is to be enabled.
- */
- public function setEnabled($value)
- {
- $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the control has custom attributes
- */
- public function getHasAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->getCount()>0;
- else
- return false;
- }
-
- /**
- * Returns the list of custom attributes.
- * Custom attributes are name-value pairs that may be rendered
- * as HTML tags' attributes.
- * @return TAttributeCollection the list of custom attributes
- */
- public function getAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('Attributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->contains($name);
- else
- return false;
- }
-
- /**
- * @return string attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->itemAt($name);
- else
- return null;
- }
-
- /**
- * Sets a custom control attribute.
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, null if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->remove($name);
- else
- return null;
- }
-
- /**
- * @return boolean whether viewstate is enabled
- */
- public function getEnableViewState($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control!==null;$control=$control->getParent())
- if($control->_flags & self::IS_DISABLE_VIEWSTATE)
- return false;
- return true;
- }
- else
- return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
- }
-
- /**
- * @param boolean set whether to enable viewstate
- */
- public function setEnableViewState($value)
- {
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
- else
- $this->_flags |= self::IS_DISABLE_VIEWSTATE;
- }
-
- /**
- * Returns a controlstate value.
- *
- * This function is mainly used in defining getter functions for control properties
- * that must be kept in controlstate.
- * @param string the name of the controlstate value to be returned
- * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
- * @return mixed the controlstate value corresponding to $key
- */
- protected function getControlState($key,$defaultValue=null)
- {
- return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
- }
-
- /**
- * Sets a controlstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in controlstate.
- * Make sure that the controlstate value must be serializable and unserializable.
- * @param string the name of the controlstate value
- * @param mixed the controlstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
- */
- protected function setControlState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- else
- $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
- }
-
- /**
- * Clears a controlstate value.
- * @param string the name of the controlstate value to be cleared
- */
- protected function clearControlState($key)
- {
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- }
-
- /**
- * Sets a value indicating whether we should keep data in viewstate.
- * When it is false, data saved via setViewState() will not be persisted.
- * By default, it is true, meaning data will be persisted across postbacks.
- * @param boolean whether data should be persisted
- */
- public function trackViewState($enabled)
- {
- $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
- }
-
- /**
- * Returns a viewstate value.
- *
- * This function is very useful in defining getter functions for component properties
- * that must be kept in viewstate.
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- public function getViewState($key,$defaultValue=null)
- {
- if(isset($this->_viewState[$key]))
- return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
- else if(isset($this->_tempState[$key]))
- {
- if(is_object($this->_tempState[$key]) && $this->_trackViewState)
- $this->_viewState[$key]=$this->_tempState[$key];
- return $this->_tempState[$key];
- }
- else
- return $defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in viewstate.
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- public function setViewState($key,$value,$defaultValue=null)
- {
- if($this->_trackViewState)
- {
- $this->_viewState[$key]=$value;
- unset($this->_tempState[$key]);
- }
- else
- {
- unset($this->_viewState[$key]);
- $this->_tempState[$key]=$value;
- }
- }
-
- /**
- * Clears a viewstate value.
- * @param string the name of the viewstate value to be cleared
- */
- public function clearViewState($key)
- {
- unset($this->_viewState[$key]);
- unset($this->_tempState[$key]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function bindProperty($name,$expression)
- {
- $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
- }
-
- /**
- * Breaks the binding between a property (or property path) and an expression.
- * @param string the property name (or property path)
- */
- public function unbindProperty($name)
- {
- unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * Unlike regular databinding, the expression bound by this method
- * is automatically evaluated during {@link prerenderRecursive()}.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function autoBindProperty($name,$expression)
- {
- $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
- }
-
- /**
- * Performs the databinding for this control.
- */
- public function dataBind()
- {
- $this->dataBindProperties();
- $this->onDataBinding(null);
- $this->dataBindChildren();
- }
-
- /**
- * Databinding properties of the control.
- */
- protected function dataBindProperties()
- {
- Prado::trace("Data bind properties",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_DATA_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Auto databinding properties of the control.
- */
- protected function autoDataBindProperties()
- {
- if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Databinding child controls.
- */
- protected function dataBindChildren()
- {
- Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof IBindable)
- $control->dataBind();
- }
- }
-
- /**
- * @return boolean whether child controls have been created
- */
- final protected function getChildControlsCreated()
- {
- return ($this->_flags & self::IS_CHILD_CREATED)!==0;
- }
-
- /**
- * Sets a value indicating whether child controls are created.
- * If false, any existing child controls will be cleared up.
- * @param boolean whether child controls are created
- */
- final protected function setChildControlsCreated($value)
- {
- if($value)
- $this->_flags |= self::IS_CHILD_CREATED;
- else
- {
- if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
- $this->getControls()->clear();
- $this->_flags &= ~self::IS_CHILD_CREATED;
- }
- }
-
- /**
- * Ensures child controls are created.
- * If child controls are not created yet, this method will invoke
- * {@link createChildControls} to create them.
- */
- public function ensureChildControls()
- {
- if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
- {
- try
- {
- $this->_flags |= self::IS_CREATING_CHILD;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->createChildControls();
- else
- $this->createChildControls();
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- }
- catch(Exception $e)
- {
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- throw $e;
- }
- }
- }
-
- /**
- * Creates child controls.
- * This method can be overriden for controls who want to have their controls.
- * Do not call this method directly. Instead, call {@link ensureChildControls}
- * to ensure child controls are created only once.
- */
- public function createChildControls()
- {
- }
-
- /**
- * Finds a control by ID path within the current naming container.
- * The current naming container is either the control itself
- * if it implements {@link INamingContainer} or the control's naming container.
- * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
- * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
- * whose naming container is 'Item1' whose naming container is 'Repeater1'.
- * @param string ID of the control to be looked up
- * @return TControl|null the control found, null if not found
- * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
- */
- public function findControl($id)
- {
- $id=strtr($id,'.',self::ID_SEPARATOR);
- $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
- if(!$container || !$container->getHasControls())
- return null;
- if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
- {
- $container->_rf[self::RF_NAMED_CONTROLS]=array();
- $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
- }
- if(($pos=strpos($id,self::ID_SEPARATOR))===false)
- return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
- else
- {
- $cid=substr($id,0,$pos);
- $sid=substr($id,$pos+1);
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
- return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
- else
- return null;
- }
- }
-
- /**
- * Finds all child and grand-child controls that are of the specified type.
- * @param string the class name
- * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
- * @return array list of controls found
- */
- public function findControlsByType($type,$strict=true)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
- $controls[]=$control;
- if(($control instanceof TControl) && $control->getHasControls())
- $controls=array_merge($controls,$control->findControlsByType($type,$strict));
- }
- }
- return $controls;
- }
-
- /**
- * Finds all child and grand-child controls with the specified ID.
- * Note, this method is different from {@link findControl} in that
- * it searches through all controls that have this control as the ancestor
- * while {@link findcontrol} only searches through controls that have this
- * control as the direct naming container.
- * @param string the ID being looked for
- * @return array list of controls found
- */
- public function findControlsByID($id)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id===$id)
- $controls[]=$control;
- $controls=array_merge($controls,$control->findControlsByID($id));
- }
- }
- }
- return $controls;
- }
-
- /**
- * Resets the control as a naming container.
- * Only framework developers should use this method.
- */
- public function clearNamingContainer()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
- $this->clearNameTable();
- }
-
- /**
- * Registers an object by a name.
- * A registered object can be accessed like a public member variable.
- * This method should only be used by framework and control developers.
- * @param string name of the object
- * @param object object to be declared
- * @see __get
- */
- public function registerObject($name,$object)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- throw new TInvalidOperationException('control_object_reregistered',$name);
- $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
- }
-
- /**
- * Unregisters an object by name.
- * @param string name of the object
- * @see registerObject
- */
- public function unregisterObject($name)
- {
- unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean whether an object has been registered with the name
- * @see registerObject
- */
- public function isObjectRegistered($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean true if the child control has been initialized.
- */
- public function getHasChildInitialized()
- {
- return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
- }
-
- /**
- * @return boolean true if the onInit event has raised.
- */
- public function getHasInitialized()
- {
- return $this->getControlStage() >= self::CS_INITIALIZED;
- }
-
- /**
- * @return boolean true if the control has loaded post data.
- */
- public function getHasLoadedPostData()
- {
- return $this->getControlStage() >= self::CS_STATE_LOADED;
- }
-
- /**
- * @return boolean true if the onLoad event has raised.
- */
- public function getHasLoaded()
- {
- return $this->getControlStage() >= self::CS_LOADED;
- }
-
- /**
- * @return boolean true if onPreRender event has raised.
- */
- public function getHasPreRendered()
- {
- return $this->getControlStage() >= self::CS_PRERENDERED;
- }
-
- /**
- * Returns the named registered object.
- * A component with explicit ID on a template will be registered to
- * the template owner. This method allows you to obtain this component
- * with the ID.
- * @return mixed the named registered object. Null if object is not found.
- */
- public function getRegisteredObject($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
- }
-
- /**
- * @return boolean whether body contents are allowed for this control. Defaults to true.
- */
- public function getAllowChildControls()
- {
- return true;
- }
-
- /**
- * Adds the object instantiated on a template to the child control collection.
- * This method overrides the parent implementation.
- * Only framework developers and control developers should use this method.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- $this->getControls()->add($object);
- }
-
- /**
- * Clears up the child state data.
- * After a control loads its state, those state that do not belong to
- * any existing child controls are stored as child state.
- * This method will remove these state.
- * Only frameworker developers and control developers should use this method.
- */
- final protected function clearChildState()
- {
- unset($this->_rf[self::RF_CHILD_STATE]);
- }
-
- /**
- * @param TControl the potential ancestor control
- * @return boolean if the control is a descendent (parent, parent of parent, etc.)
- * of the specified control
- */
- final protected function isDescendentOf($ancestor)
- {
- $control=$this;
- while($control!==$ancestor && $control->_parent)
- $control=$control->_parent;
- return $control===$ancestor;
- }
-
- /**
- * Adds a control into the child collection of the control.
- * Control lifecycles will be caught up during the addition.
- * Only framework developers should use this method.
- * @param TControl the new child control
- */
- public function addedControl($control)
- {
- if($control->_parent)
- $control->_parent->getControls()->remove($control);
- $control->_parent=$this;
- $control->_page=$this->getPage();
- $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
- if($namingContainer)
- {
- $control->_namingContainer=$namingContainer;
- if($control->_id==='')
- $control->generateAutomaticID();
- else
- $namingContainer->clearNameTable();
- $control->clearCachedUniqueID($control instanceof INamingContainer);
- }
-
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- {
- $control->initRecursive($namingContainer);
- if($this->_stage>=self::CS_STATE_LOADED)
- {
- if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
- {
- $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
- unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
- }
- else
- $state=null;
- $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if($this->_stage>=self::CS_LOADED)
- {
- $control->loadRecursive();
- if($this->_stage>=self::CS_PRERENDERED)
- $control->preRenderRecursive();
- }
- }
- }
- }
-
- /**
- * Removes a control from the child collection of the control.
- * Only framework developers should use this method.
- * @param TControl the child control removed
- */
- public function removedControl($control)
- {
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- $control->unloadRecursive();
- $control->_parent=null;
- $control->_page=null;
- $control->_namingContainer=null;
- $control->_tplControl=null;
- //$control->_stage=self::CS_CONSTRUCTED;
- if(!($control->_flags & self::IS_ID_SET))
- $control->_id='';
- else
- unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
- $control->clearCachedUniqueID(true);
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->getHasControls())
- {
- if($this instanceof INamingContainer)
- $namingContainer=$this;
- $page=$this->getPage();
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->_namingContainer=$namingContainer;
- $control->_page=$page;
- if($control->_id==='' && $namingContainer)
- $control->generateAutomaticID();
- $control->initRecursive($namingContainer);
- }
- }
- }
- if($this->_stage_stage=self::CS_CHILD_INITIALIZED;
- if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
- {
- $page->applyControlSkin($this);
- $this->_flags |= self::IS_SKIN_APPLIED;
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onInit(null);
- else
- $this->onInit(null);
- $this->_stage=self::CS_INITIALIZED;
- }
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function loadRecursive()
- {
- if($this->_stage_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onLoad(null);
- else
- $this->onLoad(null);
- }
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->loadRecursive();
- }
- }
- if($this->_stage_stage=self::CS_LOADED;
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function preRenderRecursive()
- {
- $this->autoDataBindProperties();
-
- if($this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onPreRender(null);
- else
- $this->onPreRender(null);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->preRenderRecursive();
- else if($control instanceof TCompositeLiteral)
- $control->evaluateDynamicContent();
- }
- }
- $this->addToPostDataLoader();
- }
- $this->_stage=self::CS_PRERENDERED;
- }
-
- /**
- * Add controls implementing IPostBackDataHandler to post data loaders.
- */
- protected function addToPostDataLoader()
- {
- if($this instanceof IPostBackDataHandler)
- $this->getPage()->registerPostDataLoader($this);
- }
-
- /**
- * Performs the Unload step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function unloadRecursive()
- {
- if(!($this->_flags & self::IS_ID_SET))
- $this->_id='';
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->unloadRecursive();
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onUnload(null);
- else
- $this->onUnload(null);
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * The method raises 'OnInit' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->raiseEvent('OnInit',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * The method raises 'OnLoad' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->raiseEvent('OnLoad',$this,$param);
- }
-
- /**
- * Raises 'OnDataBinding' event.
- * This method is invoked when {@link dataBind} is invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onDataBinding($param)
- {
- Prado::trace("onDataBinding()",'System.Web.UI.TControl');
- $this->raiseEvent('OnDataBinding',$this,$param);
- }
-
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * The method raises 'OnUnload' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->raiseEvent('OnUnload',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * The method raises 'OnPreRender' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->raiseEvent('OnPreRender',$this,$param);
- }
-
- /**
- * Invokes the parent's bubbleEvent method.
- * A control who wants to bubble an event must call this method in its onEvent method.
- * @param TControl sender of the event
- * @param TEventParameter event parameter
- * @see bubbleEvent
- */
- protected function raiseBubbleEvent($sender,$param)
- {
- $control=$this;
- while($control=$control->_parent)
- {
- if($control->bubbleEvent($sender,$param))
- break;
- }
- }
-
- /**
- * This method responds to a bubbled event.
- * This method should be overriden to provide customized response to a bubbled event.
- * Check the type of event parameter to determine what event is bubbled currently.
- * @param TControl sender of the event
- * @param TEventParameter event parameters
- * @return boolean true if the event bubbling is handled and no more bubbling.
- * @see raiseBubbleEvent
- */
- public function bubbleEvent($sender,$param)
- {
- return false;
- }
-
- /**
- * Broadcasts an event.
- * The event will be sent to all controls on the current page hierarchy.
- * If a control defines the event, the event will be raised for the control.
- * If a control implements {@link IBroadcastEventReceiver}, its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
- * be invoked which gives the control a chance to respond to the event.
- * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
- * event will have this event raised, and all controls implementing
- * {@link IBroadcastEventReceiver} will also have its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
- * invoked.
- * @param string name of the broadcast event
- * @param TControl sender of this event
- * @param TEventParameter event parameter
- */
- public function broadcastEvent($name,$sender,$param)
- {
- $rootControl=(($page=$this->getPage())===null)?$this:$page;
- $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
- }
-
- /**
- * Recursively broadcasts an event.
- * This method should only be used by framework developers.
- * @param string name of the broadcast event
- * @param TControl sender of the event
- * @param TBroadcastEventParameter event parameter
- */
- private function broadcastEventInternal($name,$sender,$param)
- {
- if($this->hasEvent($name))
- $this->raiseEvent($name,$sender,$param->getParameter());
- if($this instanceof IBroadcastEventReceiver)
- $this->broadcastEventReceived($sender,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->broadcastEventInternal($name,$sender,$param);
- }
- }
- }
-
- /**
- * Traverse the whole control hierarchy rooted at this control.
- * Callback function may be invoked for each control being visited.
- * A pre-callback is invoked before traversing child controls;
- * A post-callback is invoked after traversing child controls.
- * Callback functions can be global functions or class methods.
- * They must be of the following signature:
- *
- * function callback_func($control,$param) {...}
- *
- * where $control refers to the control being visited and $param
- * is the parameter that is passed originally when calling this traverse function.
- *
- * @param mixed parameter to be passed to callbacks for each control
- * @param callback callback invoked before traversing child controls. If null, it is ignored.
- * @param callback callback invoked after traversing child controls. If null, it is ignored.
- */
- protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
- {
- if($preCallback!==null)
- call_user_func($preCallback,$this,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->traverseChildControls($param,$preCallback,$postCallback);
- }
- }
- }
- if($postCallback!==null)
- call_user_func($postCallback,$this,$param);
- }
-
- /**
- * Renders the control.
- * Only when the control is visible will the control be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderControl($writer)
- {
- if($this instanceof IActiveControl || $this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->render($writer);
- else
- $this->render($writer);
- }
- }
-
- /**
- * Renders the control.
- * This method is invoked by {@link renderControl} when the control is visible.
- * You can override this method to provide customized rendering of the control.
- * By default, the control simply renders all its child contents.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $this->renderChildren($writer);
- }
-
- /**
- * Renders the children of the control.
- * This method iterates through all child controls and static text strings
- * and renders them in order.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderChildren($writer)
- {
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_string($control))
- $writer->write($control);
- else if($control instanceof TControl)
- $control->renderControl($writer);
- else if($control instanceof IRenderable)
- $control->render($writer);
- }
- }
- }
-
- /**
- * This method is invoked when control state is to be saved.
- * You can override this method to do last step state saving.
- * Parent implementation must be invoked.
- */
- public function saveState()
- {
- }
-
- /**
- * This method is invoked right after the control has loaded its state.
- * You can override this method to initialize data from the control state.
- * Parent implementation must be invoked.
- */
- public function loadState()
- {
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- if(is_array($state))
- {
- // A null state means the stateful properties all take default values.
- // So if the state is enabled, we have to assign the null value.
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if(isset($state[1]))
- {
- $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
- unset($state[1]);
- }
- else
- unset($this->_rf[self::RF_CONTROLSTATE]);
- if($needViewState)
- {
- if(isset($state[0]))
- $this->_viewState=&$state[0];
- else
- $this->_viewState=array();
- }
- unset($state[0]);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if(isset($state[$control->_id]))
- {
- $control->loadStateRecursive($state[$control->_id],$needViewState);
- unset($state[$control->_id]);
- }
- }
- }
- }
- if(!empty($state))
- $this->_rf[self::RF_CHILD_STATE]=&$state;
- }
- $this->_stage=self::CS_STATE_LOADED;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->loadState();
- else
- $this->loadState();
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->saveState();
- else
- $this->saveState();
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- $state=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $state[$control->_id]=&$control->saveStateRecursive($needViewState);
- }
- }
- if($needViewState && !empty($this->_viewState))
- $state[0]=&$this->_viewState;
- if(isset($this->_rf[self::RF_CONTROLSTATE]))
- $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
- return $state;
- }
-
- /**
- * Applies a stylesheet skin to a control.
- * @param TPage the page containing the control
- * @throws TInvalidOperationException if the stylesheet skin is applied already
- */
- public function applyStyleSheetSkin($page)
- {
- if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
- {
- $page->applyControlStyleSheet($this);
- $this->_flags |= self::IS_STYLESHEET_APPLIED;
- }
- else if($this->_flags & self::IS_STYLESHEET_APPLIED)
- throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
- }
-
- /**
- * Clears the cached UniqueID.
- * If $recursive=true, all children's cached UniqueID will be cleared as well.
- * @param boolean whether the clearing is recursive.
- */
- private function clearCachedUniqueID($recursive)
- {
- if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->clearCachedUniqueID($recursive);
- }
- $this->_uid=null;
- }
-
- /**
- * Generates an automatic ID for the control.
- */
- private function generateAutomaticID()
- {
- $this->_flags &= ~self::IS_ID_SET;
- if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
- $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
- $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
- $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Clears the list of the controls whose IDs are managed by the specified naming container.
- */
- private function clearNameTable()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS]);
- }
-
- /**
- * Updates the list of the controls whose IDs are managed by the specified naming container.
- * @param TControl the naming container
- * @param TControlCollection list of controls
- * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
- */
- private function fillNameTable($container,$controls)
- {
- foreach($controls as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id!=='')
- {
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
- throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
- else
- $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
- }
- if(!($control instanceof INamingContainer) && $control->getHasControls())
- $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
- }
- }
- }
-}
-
-
-/**
- * TControlCollection class
- *
- * TControlCollection implements a collection that enables
- * controls to maintain a list of their child controls.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControlCollection extends TList
-{
- /**
- * the control that owns this collection.
- * @var TControl
- */
- private $_o;
-
- /**
- * Constructor.
- * @param TControl the control that owns this collection.
- * @param boolean whether the list is read-only
- */
- public function __construct(TControl $owner,$readOnly=false)
- {
- $this->_o=$owner;
- parent::__construct(null,$readOnly);
- }
-
- /**
- * @return TControl the control that owns this collection.
- */
- protected function getOwner()
- {
- return $this->_o;
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added child control.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- {
- parent::insertAt($index,$item);
- $this->_o->addedControl($item);
- }
- else if(is_string($item) || ($item instanceof IRenderable))
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('controlcollection_control_required');
- }
-
- /**
- * Removes an item at the specified position.
- * This overrides the parent implementation by performing additional
- * cleanup work when removing a child control.
- * @param integer the index of the item to be removed.
- * @return mixed the removed item.
- */
- public function removeAt($index)
- {
- $item=parent::removeAt($index);
- if($item instanceof TControl)
- $this->_o->removedControl($item);
- return $item;
- }
-
- /**
- * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer}
- */
- public function clear()
- {
- parent::clear();
- if($this->_o instanceof INamingContainer)
- $this->_o->clearNamingContainer();
- }
-}
-
-/**
- * TEmptyControlCollection class
- *
- * TEmptyControlCollection implements an empty control list that prohibits adding
- * controls to it. This is useful for controls that do not allow child controls.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TEmptyControlCollection extends TControlCollection
-{
- /**
- * Constructor.
- * @param TControl the control that owns this collection.
- */
- public function __construct(TControl $owner)
- {
- parent::__construct($owner,true);
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by ignoring new addition.
- * @param integer the speicified position.
- * @param mixed new item
- */
- public function insertAt($index,$item)
- {
- if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case
- parent::insertAt($index,$item); // this will generate an exception in parent implementation
- }
-}
-
-/**
- * INamingContainer interface.
- * INamingContainer marks a control as a naming container.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface INamingContainer
-{
-}
-
-/**
- * IPostBackEventHandler interface
- *
- * If a control wants to respond to postback event, it must implement this interface.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IPostBackEventHandler
-{
- /**
- * Raises postback event.
- * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand)
- * indicating the component is responsible for the postback event.
- * @param string the parameter associated with the postback event
- */
- public function raisePostBackEvent($param);
-}
-
-/**
- * IPostBackDataHandler interface
- *
- * If a control wants to load post data, it must implement this interface.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IPostBackDataHandler
-{
- /**
- * Loads user input data.
- * The implementation of this function can use $values[$key] to get the user input
- * data that are meant for the particular control.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values);
- /**
- * Raises postdata changed event.
- * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged)
- * indicating the control data is changed.
- */
- public function raisePostDataChangedEvent();
- /**
- * @return boolean whether postback causes the data change. Defaults to false for non-postback state.
- */
- public function getDataChanged();
-}
-
-
-/**
- * IValidator interface
- *
- * If a control wants to validate user input, it must implement this interface.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IValidator
-{
- /**
- * Validates certain data.
- * The implementation of this function should validate certain data
- * (e.g. data entered into TTextBox control).
- * @return boolean whether the data passes the validation
- */
- public function validate();
- /**
- * @return boolean whether the previous {@link validate()} is successful.
- */
- public function getIsValid();
- /**
- * @param boolean whether the validator validates successfully
- */
- public function setIsValid($value);
- /**
- * @return string error message during last validate
- */
- public function getErrorMessage();
- /**
- * @param string error message for the validation
- */
- public function setErrorMessage($value);
-}
-
-
-/**
- * IValidatable interface
- *
- * If a control wants to be validated by a validator, it must implement this interface.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IValidatable
-{
- /**
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue();
- /**
- * @return boolean wether this control's validators validated successfully (must default to true)
- */
- public function getIsValid();
- /**
- * @return boolean wether this control's validators validated successfully
- */
- public function setIsValid($value);
-}
-
-/**
- * IBroadcastEventReceiver interface
- *
- * If a control wants to check broadcast event, it must implement this interface.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IBroadcastEventReceiver
-{
- /**
- * Handles broadcast event.
- * This method is invoked automatically when an event is broadcasted.
- * Within this method, you may check the event name given in
- * the event parameter to determine whether you should respond to
- * this event.
- * @param TControl sender of the event
- * @param TBroadCastEventParameter event parameter
- */
- public function broadcastEventReceived($sender,$param);
-}
-
-/**
- * ITheme interface.
- *
- * This interface must be implemented by theme.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface ITheme
-{
- /**
- * Applies this theme to the specified control.
- * @param TControl the control to be applied with this theme
- */
- public function applySkin($control);
-}
-
-/**
- * ITemplate interface
- *
- * ITemplate specifies the interface for classes encapsulating
- * parsed template structures.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface ITemplate
-{
- /**
- * Instantiates the template.
- * Content in the template will be instantiated as components and text strings
- * and passed to the specified parent control.
- * @param TControl the parent control
- */
- public function instantiateIn($parent);
-}
-
-/**
- * IButtonControl interface
- *
- * IButtonControl specifies the common properties and events that must
- * be implemented by a button control, such as {@link TButton}, {@link TLinkButton},
- * {@link TImageButton}.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IButtonControl
-{
- /**
- * @return string caption of the button
- */
- public function getText();
-
- /**
- * @param string caption of the button
- */
- public function setText($value);
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation
- */
- public function getCausesValidation();
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value);
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName();
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value);
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter();
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value);
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup();
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value);
-
- /**
- * Raises OnClick event.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param);
-
- /**
- * Raises OnCommand event.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param);
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value);
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton();
-}
-
-/**
- * ISurroundable interface
- *
- * Identifies controls that may create an additional surrounding tag. The id of the
- * tag can be obtained with {@link getSurroundingTagID}.
- *
- * @package System.Web.UI
- * @since 3.1.2
- */
-interface ISurroundable
-{
- /**
- * @return string the id of the embedding tag of the control or the control's clientID if not surrounded
- */
- public function getSurroundingTagID();
-}
-
-/**
- * TBroadcastEventParameter class
- *
- * TBroadcastEventParameter encapsulates the parameter data for
- * events that are broadcasted. The name of of the event is specified via
- * {@link setName Name} property while the event parameter is via
- * {@link setParameter Parameter} property.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TBroadcastEventParameter extends TEventParameter
-{
- private $_name;
- private $_param;
-
- /**
- * Constructor.
- * @param string name of the broadcast event
- * @param mixed parameter of the broadcast event
- */
- public function __construct($name='',$parameter=null)
- {
- $this->_name=$name;
- $this->_param=$parameter;
- }
-
- /**
- * @return string name of the broadcast event
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string name of the broadcast event
- */
- public function setName($value)
- {
- $this->_name=$value;
- }
-
- /**
- * @return mixed parameter of the broadcast event
- */
- public function getParameter()
- {
- return $this->_param;
- }
-
- /**
- * @param mixed parameter of the broadcast event
- */
- public function setParameter($value)
- {
- $this->_param=$value;
- }
-}
-
-/**
- * TCommandEventParameter class
- *
- * TCommandEventParameter encapsulates the parameter data for Command
- * event of button controls. You can access the name of the command via
- * {@link getCommandName CommandName} property, and the parameter carried
- * with the command via {@link getCommandParameter CommandParameter} property.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCommandEventParameter extends TEventParameter
-{
- private $_name;
- private $_param;
-
- /**
- * Constructor.
- * @param string name of the command
- * @param string parameter of the command
- */
- public function __construct($name='',$parameter='')
- {
- $this->_name=$name;
- $this->_param=$parameter;
- }
-
- /**
- * @return string name of the command
- */
- public function getCommandName()
- {
- return $this->_name;
- }
-
- /**
- * @return string parameter of the command
- */
- public function getCommandParameter()
- {
- return $this->_param;
- }
-}
-
-
-/**
- * TCompositeLiteral class
- *
- * TCompositeLiteral is used internally by {@link TTemplate} for representing
- * consecutive static strings, expressions and statements.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeLiteral extends TComponent implements IRenderable, IBindable
-{
- const TYPE_EXPRESSION=0;
- const TYPE_STATEMENTS=1;
- const TYPE_DATABINDING=2;
- private $_container=null;
- private $_items=array();
- private $_expressions=array();
- private $_statements=array();
- private $_bindings=array();
-
- /**
- * Constructor.
- * @param array list of items to be represented by TCompositeLiteral
- */
- public function __construct($items)
- {
- $this->_items=array();
- $this->_expressions=array();
- $this->_statements=array();
- foreach($items as $id=>$item)
- {
- if(is_array($item))
- {
- if($item[0]===self::TYPE_EXPRESSION)
- $this->_expressions[$id]=$item[1];
- else if($item[0]===self::TYPE_STATEMENTS)
- $this->_statements[$id]=$item[1];
- else if($item[0]===self::TYPE_DATABINDING)
- $this->_bindings[$id]=$item[1];
- $this->_items[$id]='';
- }
- else
- $this->_items[$id]=$item;
- }
- }
-
- /**
- * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function getContainer()
- {
- return $this->_container;
- }
-
- /**
- * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function setContainer(TComponent $value)
- {
- $this->_container=$value;
- }
-
- /**
- * Evaluates the expressions and/or statements in the component.
- */
- public function evaluateDynamicContent()
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_expressions as $id=>$expression)
- $this->_items[$id]=$context->evaluateExpression($expression);
- foreach($this->_statements as $id=>$statement)
- $this->_items[$id]=$context->evaluateStatements($statement);
- }
-
- /**
- * Performs databindings.
- * This method is required by {@link IBindable}
- */
- public function dataBind()
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_bindings as $id=>$binding)
- $this->_items[$id]=$context->evaluateExpression($binding);
- }
-
- /**
- * Renders the content stored in this component.
- * This method is required by {@link IRenderable}
- * @param ITextWriter
- */
- public function render($writer)
- {
- $writer->write(implode('',$this->_items));
- }
-}
-
-?>
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TAttributeCollection and TControlAdapter class
+ */
+Prado::using('System.Collections.TAttributeCollection');
+Prado::using('System.Web.UI.TControlAdapter');
+
+/**
+ * TControl class
+ *
+ * TControl is the base class for all components on a page hierarchy.
+ * It implements the following features for UI-related functionalities:
+ * - databinding feature
+ * - parent and child relationship
+ * - naming container and containee relationship
+ * - viewstate and controlstate features
+ * - rendering scheme
+ * - control lifecycles
+ *
+ * A property can be data-bound with an expression. By calling {@link dataBind},
+ * expressions bound to properties will be evaluated and the results will be
+ * set to the corresponding properties.
+ *
+ * Parent and child relationship determines how the presentation of controls are
+ * enclosed within each other. A parent will determine where to place
+ * the presentation of its child controls. For example, a TPanel will enclose
+ * all its child controls' presentation within a div html tag. A control's parent
+ * can be obtained via {@link getParent Parent} property, and its
+ * {@link getControls Controls} property returns a list of the control's children,
+ * including controls and static texts. The property can be manipulated
+ * like an array for adding or removing a child (see {@link TList} for more details).
+ *
+ * A naming container control implements INamingContainer and ensures that
+ * its containee controls can be differentiated by their ID property values.
+ * Naming container and containee realtionship specifies a protocol to uniquely
+ * identify an arbitrary control on a page hierarchy by an ID path (concatenation
+ * of all naming containers' IDs and the target control's ID).
+ *
+ * Viewstate and controlstate are two approaches to preserve state across
+ * page postback requests. ViewState is mainly related with UI specific state
+ * and can be disabled if not needed. ControlState represents crucial logic state
+ * and cannot be disabled.
+ *
+ * A control is rendered via its {@link render()} method (the method is invoked
+ * by the framework.) Descendant control classes may override this method for
+ * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
+ * which is responsible for rendering of children of the control.
+ * Control's {@link getVisible Visible} property governs whether the control
+ * should be rendered or not.
+ *
+ * Each control on a page will undergo a series of lifecycles, including
+ * control construction, Init, Load, PreRender, Render, and OnUnload.
+ * They work together with page lifecycles to process a page request.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControl extends TApplicationComponent implements IRenderable, IBindable
+{
+ /**
+ * format of control ID
+ */
+ const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
+ /**
+ * separator char between IDs in a UniqueID
+ */
+ const ID_SEPARATOR='$';
+ /**
+ * separator char between IDs in a ClientID
+ */
+ const CLIENT_ID_SEPARATOR='_';
+ /**
+ * prefix to an ID automatically generated
+ */
+ const AUTOMATIC_ID_PREFIX='ctl';
+
+ /**
+ * the stage of lifecycles that the control is currently at
+ */
+ const CS_CONSTRUCTED=0;
+ const CS_CHILD_INITIALIZED=1;
+ const CS_INITIALIZED=2;
+ const CS_STATE_LOADED=3;
+ const CS_LOADED=4;
+ const CS_PRERENDERED=5;
+
+ /**
+ * State bits.
+ */
+ const IS_ID_SET=0x01;
+ const IS_DISABLE_VIEWSTATE=0x02;
+ const IS_SKIN_APPLIED=0x04;
+ const IS_STYLESHEET_APPLIED=0x08;
+ const IS_DISABLE_THEMING=0x10;
+ const IS_CHILD_CREATED=0x20;
+ const IS_CREATING_CHILD=0x40;
+
+ /**
+ * Indexes for the rare fields.
+ * In order to save memory, rare fields will only be created if they are needed.
+ */
+ const RF_CONTROLS=0; // child controls
+ const RF_CHILD_STATE=1; // child state field
+ const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
+ const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
+ const RF_SKIN_ID=4; // skin ID
+ const RF_DATA_BINDINGS=5; // data bindings
+ const RF_EVENTS=6; // event handlers
+ const RF_CONTROLSTATE=7; // controlstate
+ const RF_NAMED_OBJECTS=8; // controls declared with ID on template
+ const RF_ADAPTER=9; // adapter
+ const RF_AUTO_BINDINGS=10; // auto data bindings
+
+ /**
+ * @var string control ID
+ */
+ private $_id='';
+ /**
+ * @var string control unique ID
+ */
+ private $_uid;
+ /**
+ * @var TControl parent of the control
+ */
+ private $_parent;
+ /**
+ * @var TPage page that the control resides in
+ */
+ private $_page;
+ /**
+ * @var TControl naming container of the control
+ */
+ private $_namingContainer;
+ /**
+ * @var TTemplateControl control whose template contains the control
+ */
+ private $_tplControl;
+ /**
+ * @var array viewstate data
+ */
+ private $_viewState=array();
+ /**
+ * @var array temporary state (usually set in template)
+ */
+ private $_tempState=array();
+ /**
+ * @var boolean whether we should keep state in viewstate
+ */
+ private $_trackViewState=true;
+ /**
+ * @var integer the current stage of the control lifecycles
+ */
+ private $_stage=0;
+ /**
+ * @var integer representation of the state bits
+ */
+ private $_flags=0;
+ /**
+ * @var array a collection of rare control data
+ */
+ private $_rf=array();
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ }
+
+ /**
+ * Returns a property value by name or a control by ID.
+ * This overrides the parent implementation by allowing accessing
+ * a control via its ID using the following syntax,
+ *
+ * $menuBar=$this->menuBar;
+ *
+ * Note, the control must be configured in the template
+ * with explicit ID. If the name matches both a property and a control ID,
+ * the control ID will take the precedence.
+ *
+ * @param string the property name or control ID
+ * @return mixed the property value or the target control
+ * @throws TInvalidOperationException if the property is not defined.
+ * @see registerObject
+ */
+ public function __get($name)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ return $this->_rf[self::RF_NAMED_OBJECTS][$name];
+ else
+ return parent::__get($name);
+ }
+
+ /**
+ * @return boolean whether there is an adapter for this control
+ */
+ public function getHasAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER]);
+ }
+
+ /**
+ * @return TControlAdapter control adapter. Null if not exists.
+ */
+ public function getAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
+ }
+
+ /**
+ * @param TControlAdapter control adapter
+ */
+ public function setAdapter(TControlAdapter $adapter)
+ {
+ $this->_rf[self::RF_ADAPTER]=$adapter;
+ }
+
+ /**
+ * @return TControl the parent of this control
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * @return TControl the naming container of this control
+ */
+ public function getNamingContainer()
+ {
+ if(!$this->_namingContainer && $this->_parent)
+ {
+ if($this->_parent instanceof INamingContainer)
+ $this->_namingContainer=$this->_parent;
+ else
+ $this->_namingContainer=$this->_parent->getNamingContainer();
+ }
+ return $this->_namingContainer;
+ }
+
+ /**
+ * @return TPage the page that contains this control
+ */
+ public function getPage()
+ {
+ if(!$this->_page)
+ {
+ if($this->_parent)
+ $this->_page=$this->_parent->getPage();
+ else if($this->_tplControl)
+ $this->_page=$this->_tplControl->getPage();
+ }
+ return $this->_page;
+ }
+
+ /**
+ * Sets the page for a control.
+ * Only framework developers should use this method.
+ * @param TPage the page that contains this control
+ */
+ public function setPage($page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Sets the control whose template contains this control.
+ * Only framework developers should use this method.
+ * @param TTemplateControl the control whose template contains this control
+ */
+ public function setTemplateControl($control)
+ {
+ $this->_tplControl=$control;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template contains this control
+ */
+ public function getTemplateControl()
+ {
+ if(!$this->_tplControl && $this->_parent)
+ $this->_tplControl=$this->_parent->getTemplateControl();
+ return $this->_tplControl;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template is loaded from
+ * some external storage, such as file, db, and whose template ultimately
+ * contains this control.
+ */
+ public function getSourceTemplateControl()
+ {
+ $control=$this;
+ while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
+ {
+ if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
+ return $control;
+ }
+ return $this->getPage();
+ }
+
+ /**
+ * Gets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @return integer the lifecycle step the control is currently at.
+ * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function getControlStage()
+ {
+ return $this->_stage;
+ }
+
+ /**
+ * Sets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @param integer the lifecycle step the control is currently at.
+ * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function setControlStage($value)
+ {
+ $this->_stage=$value;
+ }
+
+ /**
+ * Returns the id of the control.
+ * Control ID can be either manually set or automatically generated.
+ * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
+ * @param boolean whether to hide automatically generated ID
+ * @return string the ID of the control
+ */
+ public function getID($hideAutoID=true)
+ {
+ if($hideAutoID)
+ return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
+ else
+ return $this->_id;
+ }
+
+ /**
+ * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
+ * @throws TInvalidDataValueException if ID is in a bad format
+ */
+ public function setID($id)
+ {
+ if(!preg_match(self::ID_FORMAT,$id))
+ throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
+ $this->_id=$id;
+ $this->_flags |= self::IS_ID_SET;
+ $this->clearCachedUniqueID($this instanceof INamingContainer);
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Returns a unique ID that identifies the control in the page hierarchy.
+ * A unique ID is the contenation of all naming container controls' IDs and the control ID.
+ * These IDs are separated by '$' character.
+ * Control users should not rely on the specific format of UniqueID, however.
+ * @return string a unique ID that identifies the control in the page hierarchy
+ */
+ public function getUniqueID()
+ {
+ if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
+ {
+ $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
+ if($namingContainer=$this->getNamingContainer())
+ {
+ if($this->getPage()===$namingContainer)
+ return ($this->_uid=$this->_id);
+ else if(($prefix=$namingContainer->getUniqueID())==='')
+ return $this->_id;
+ else
+ return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
+ }
+ else // no naming container
+ return $this->_id;
+ }
+ else
+ return $this->_uid;
+ }
+
+ /**
+ * Sets input focus to this control.
+ */
+ public function focus()
+ {
+ $this->getPage()->setFocus($this);
+ }
+
+ /**
+ * Returns the client ID of the control.
+ * The client ID can be used to uniquely identify
+ * the control in client-side scripts (such as JavaScript).
+ * Do not rely on the explicit format of the return ID.
+ * @return string the client ID of the control
+ */
+ public function getClientID()
+ {
+ return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * Converts a unique ID to a client ID.
+ * @param string the unique ID of a control
+ * @return string the client ID of the control
+ */
+ public static function convertUniqueIdToClientId($uniqueID)
+ {
+ return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * @return string the skin ID of this control, '' if not set
+ */
+ public function getSkinID()
+ {
+ return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function setSkinID($value)
+ {
+ if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
+ else
+ $this->_rf[self::RF_SKIN_ID]=$value;
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function getIsSkinApplied()
+ {
+ return ($this->_flags & self::IS_SKIN_APPLIED);
+ }
+
+ /**
+ * @return boolean whether theming is enabled for this control.
+ * The theming is enabled if the control and all its parents have it enabled.
+ */
+ public function getEnableTheming()
+ {
+ if($this->_flags & self::IS_DISABLE_THEMING)
+ return false;
+ else
+ return $this->_parent?$this->_parent->getEnableTheming():true;
+ }
+
+ /**
+ * @param boolean whether to enable theming
+ * @throws TInvalidOperationException if this method is invoked after OnPreInit
+ */
+ public function setEnableTheming($value)
+ {
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
+ else if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_THEMING;
+ else
+ $this->_flags |= self::IS_DISABLE_THEMING;
+ }
+
+ /**
+ * Returns custom data associated with this control.
+ * A control may be associated with some custom data for various purposes.
+ * For example, a button may be associated with a string to identify itself
+ * in a generic OnClick event handler.
+ * @return mixed custom data associated with this control. Defaults to null.
+ */
+ public function getCustomData()
+ {
+ return $this->getViewState('CustomData',null);
+ }
+
+ /**
+ * Associates custom data with this control.
+ * Note, the custom data must be serializable and unserializable.
+ * @param mixed custom data
+ */
+ public function setCustomData($value)
+ {
+ $this->setViewState('CustomData',$value,null);
+ }
+
+ /**
+ * @return boolean whether the control has child controls
+ */
+ public function getHasControls()
+ {
+ return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
+ }
+
+ /**
+ * @return TControlCollection the child control collection
+ */
+ public function getControls()
+ {
+ if(!isset($this->_rf[self::RF_CONTROLS]))
+ $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
+ return $this->_rf[self::RF_CONTROLS];
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TControlCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
+ }
+
+ /**
+ * Checks if a control is visible.
+ * If parent check is required, then a control is visible only if the control
+ * and all its ancestors are visible.
+ * @param boolean whether the parents should also be checked if visible
+ * @return boolean whether the control is visible (default=true).
+ */
+ public function getVisible($checkParents=true)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getVisible(false))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the control is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a value indicating whether the control is enabled.
+ * A control is enabled if it allows client user interaction.
+ * If $checkParents is true, all parent controls will be checked,
+ * and unless they are all enabled, false will be returned.
+ * The property Enabled is mainly used for {@link TWebControl}
+ * derived controls.
+ * @param boolean whether the parents should also be checked enabled
+ * @return boolean whether the control is enabled.
+ */
+ public function getEnabled($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getViewState('Enabled',true))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Enabled',true);
+ }
+
+ /**
+ * @param boolean whether the control is to be enabled.
+ */
+ public function setEnabled($value)
+ {
+ $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the control has custom attributes
+ */
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the list of custom attributes.
+ * Custom attributes are name-value pairs that may be rendered
+ * as HTML tags' attributes.
+ * @return TAttributeCollection the list of custom attributes
+ */
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * Sets a custom control attribute.
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, null if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether viewstate is enabled
+ */
+ public function getEnableViewState($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control!==null;$control=$control->getParent())
+ if($control->_flags & self::IS_DISABLE_VIEWSTATE)
+ return false;
+ return true;
+ }
+ else
+ return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
+ }
+
+ /**
+ * @param boolean set whether to enable viewstate
+ */
+ public function setEnableViewState($value)
+ {
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
+ else
+ $this->_flags |= self::IS_DISABLE_VIEWSTATE;
+ }
+
+ /**
+ * Returns a controlstate value.
+ *
+ * This function is mainly used in defining getter functions for control properties
+ * that must be kept in controlstate.
+ * @param string the name of the controlstate value to be returned
+ * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
+ * @return mixed the controlstate value corresponding to $key
+ */
+ protected function getControlState($key,$defaultValue=null)
+ {
+ return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a controlstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in controlstate.
+ * Make sure that the controlstate value must be serializable and unserializable.
+ * @param string the name of the controlstate value
+ * @param mixed the controlstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
+ */
+ protected function setControlState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ else
+ $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
+ }
+
+ /**
+ * Clears a controlstate value.
+ * @param string the name of the controlstate value to be cleared
+ */
+ protected function clearControlState($key)
+ {
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ }
+
+ /**
+ * Sets a value indicating whether we should keep data in viewstate.
+ * When it is false, data saved via setViewState() will not be persisted.
+ * By default, it is true, meaning data will be persisted across postbacks.
+ * @param boolean whether data should be persisted
+ */
+ public function trackViewState($enabled)
+ {
+ $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * This function is very useful in defining getter functions for component properties
+ * that must be kept in viewstate.
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ public function getViewState($key,$defaultValue=null)
+ {
+ if(isset($this->_viewState[$key]))
+ return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
+ else if(isset($this->_tempState[$key]))
+ {
+ if(is_object($this->_tempState[$key]) && $this->_trackViewState)
+ $this->_viewState[$key]=$this->_tempState[$key];
+ return $this->_tempState[$key];
+ }
+ else
+ return $defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in viewstate.
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ public function setViewState($key,$value,$defaultValue=null)
+ {
+ if($this->_trackViewState)
+ {
+ $this->_viewState[$key]=$value;
+ unset($this->_tempState[$key]);
+ }
+ else
+ {
+ unset($this->_viewState[$key]);
+ $this->_tempState[$key]=$value;
+ }
+ }
+
+ /**
+ * Clears a viewstate value.
+ * @param string the name of the viewstate value to be cleared
+ */
+ public function clearViewState($key)
+ {
+ unset($this->_viewState[$key]);
+ unset($this->_tempState[$key]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function bindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Breaks the binding between a property (or property path) and an expression.
+ * @param string the property name (or property path)
+ */
+ public function unbindProperty($name)
+ {
+ unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * Unlike regular databinding, the expression bound by this method
+ * is automatically evaluated during {@link prerenderRecursive()}.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Performs the databinding for this control.
+ */
+ public function dataBind()
+ {
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+ $this->dataBindChildren();
+ }
+
+ /**
+ * Databinding properties of the control.
+ */
+ protected function dataBindProperties()
+ {
+ Prado::trace("Data bind properties",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_DATA_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Auto databinding properties of the control.
+ */
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Databinding child controls.
+ */
+ protected function dataBindChildren()
+ {
+ Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof IBindable)
+ $control->dataBind();
+ }
+ }
+
+ /**
+ * @return boolean whether child controls have been created
+ */
+ final protected function getChildControlsCreated()
+ {
+ return ($this->_flags & self::IS_CHILD_CREATED)!==0;
+ }
+
+ /**
+ * Sets a value indicating whether child controls are created.
+ * If false, any existing child controls will be cleared up.
+ * @param boolean whether child controls are created
+ */
+ final protected function setChildControlsCreated($value)
+ {
+ if($value)
+ $this->_flags |= self::IS_CHILD_CREATED;
+ else
+ {
+ if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
+ $this->getControls()->clear();
+ $this->_flags &= ~self::IS_CHILD_CREATED;
+ }
+ }
+
+ /**
+ * Ensures child controls are created.
+ * If child controls are not created yet, this method will invoke
+ * {@link createChildControls} to create them.
+ */
+ public function ensureChildControls()
+ {
+ if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
+ {
+ try
+ {
+ $this->_flags |= self::IS_CREATING_CHILD;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->createChildControls();
+ else
+ $this->createChildControls();
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ }
+ catch(Exception $e)
+ {
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * Creates child controls.
+ * This method can be overriden for controls who want to have their controls.
+ * Do not call this method directly. Instead, call {@link ensureChildControls}
+ * to ensure child controls are created only once.
+ */
+ public function createChildControls()
+ {
+ }
+
+ /**
+ * Finds a control by ID path within the current naming container.
+ * The current naming container is either the control itself
+ * if it implements {@link INamingContainer} or the control's naming container.
+ * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
+ * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
+ * whose naming container is 'Item1' whose naming container is 'Repeater1'.
+ * @param string ID of the control to be looked up
+ * @return TControl|null the control found, null if not found
+ * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
+ */
+ public function findControl($id)
+ {
+ $id=strtr($id,'.',self::ID_SEPARATOR);
+ $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
+ if(!$container || !$container->getHasControls())
+ return null;
+ if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
+ {
+ $container->_rf[self::RF_NAMED_CONTROLS]=array();
+ $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
+ }
+ if(($pos=strpos($id,self::ID_SEPARATOR))===false)
+ return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
+ else
+ {
+ $cid=substr($id,0,$pos);
+ $sid=substr($id,$pos+1);
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
+ return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Finds all child and grand-child controls that are of the specified type.
+ * @param string the class name
+ * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
+ * @return array list of controls found
+ */
+ public function findControlsByType($type,$strict=true)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
+ $controls[]=$control;
+ if(($control instanceof TControl) && $control->getHasControls())
+ $controls=array_merge($controls,$control->findControlsByType($type,$strict));
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Finds all child and grand-child controls with the specified ID.
+ * Note, this method is different from {@link findControl} in that
+ * it searches through all controls that have this control as the ancestor
+ * while {@link findcontrol} only searches through controls that have this
+ * control as the direct naming container.
+ * @param string the ID being looked for
+ * @return array list of controls found
+ */
+ public function findControlsByID($id)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id===$id)
+ $controls[]=$control;
+ $controls=array_merge($controls,$control->findControlsByID($id));
+ }
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Resets the control as a naming container.
+ * Only framework developers should use this method.
+ */
+ public function clearNamingContainer()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
+ $this->clearNameTable();
+ }
+
+ /**
+ * Registers an object by a name.
+ * A registered object can be accessed like a public member variable.
+ * This method should only be used by framework and control developers.
+ * @param string name of the object
+ * @param object object to be declared
+ * @see __get
+ */
+ public function registerObject($name,$object)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ throw new TInvalidOperationException('control_object_reregistered',$name);
+ $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
+ }
+
+ /**
+ * Unregisters an object by name.
+ * @param string name of the object
+ * @see registerObject
+ */
+ public function unregisterObject($name)
+ {
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean whether an object has been registered with the name
+ * @see registerObject
+ */
+ public function isObjectRegistered($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean true if the child control has been initialized.
+ */
+ public function getHasChildInitialized()
+ {
+ return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the onInit event has raised.
+ */
+ public function getHasInitialized()
+ {
+ return $this->getControlStage() >= self::CS_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the control has loaded post data.
+ */
+ public function getHasLoadedPostData()
+ {
+ return $this->getControlStage() >= self::CS_STATE_LOADED;
+ }
+
+ /**
+ * @return boolean true if the onLoad event has raised.
+ */
+ public function getHasLoaded()
+ {
+ return $this->getControlStage() >= self::CS_LOADED;
+ }
+
+ /**
+ * @return boolean true if onPreRender event has raised.
+ */
+ public function getHasPreRendered()
+ {
+ return $this->getControlStage() >= self::CS_PRERENDERED;
+ }
+
+ /**
+ * Returns the named registered object.
+ * A component with explicit ID on a template will be registered to
+ * the template owner. This method allows you to obtain this component
+ * with the ID.
+ * @return mixed the named registered object. Null if object is not found.
+ */
+ public function getRegisteredObject($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
+ }
+
+ /**
+ * @return boolean whether body contents are allowed for this control. Defaults to true.
+ */
+ public function getAllowChildControls()
+ {
+ return true;
+ }
+
+ /**
+ * Adds the object instantiated on a template to the child control collection.
+ * This method overrides the parent implementation.
+ * Only framework developers and control developers should use this method.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Clears up the child state data.
+ * After a control loads its state, those state that do not belong to
+ * any existing child controls are stored as child state.
+ * This method will remove these state.
+ * Only frameworker developers and control developers should use this method.
+ */
+ final protected function clearChildState()
+ {
+ unset($this->_rf[self::RF_CHILD_STATE]);
+ }
+
+ /**
+ * @param TControl the potential ancestor control
+ * @return boolean if the control is a descendent (parent, parent of parent, etc.)
+ * of the specified control
+ */
+ final protected function isDescendentOf($ancestor)
+ {
+ $control=$this;
+ while($control!==$ancestor && $control->_parent)
+ $control=$control->_parent;
+ return $control===$ancestor;
+ }
+
+ /**
+ * Adds a control into the child collection of the control.
+ * Control lifecycles will be caught up during the addition.
+ * Only framework developers should use this method.
+ * @param TControl the new child control
+ */
+ public function addedControl($control)
+ {
+ if($control->_parent)
+ $control->_parent->getControls()->remove($control);
+ $control->_parent=$this;
+ $control->_page=$this->getPage();
+ $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
+ if($namingContainer)
+ {
+ $control->_namingContainer=$namingContainer;
+ if($control->_id==='')
+ $control->generateAutomaticID();
+ else
+ $namingContainer->clearNameTable();
+ $control->clearCachedUniqueID($control instanceof INamingContainer);
+ }
+
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ {
+ $control->initRecursive($namingContainer);
+ if($this->_stage>=self::CS_STATE_LOADED)
+ {
+ if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
+ {
+ $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
+ unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
+ }
+ else
+ $state=null;
+ $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if($this->_stage>=self::CS_LOADED)
+ {
+ $control->loadRecursive();
+ if($this->_stage>=self::CS_PRERENDERED)
+ $control->preRenderRecursive();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a control from the child collection of the control.
+ * Only framework developers should use this method.
+ * @param TControl the child control removed
+ */
+ public function removedControl($control)
+ {
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ $control->unloadRecursive();
+ $control->_parent=null;
+ $control->_page=null;
+ $control->_namingContainer=null;
+ $control->_tplControl=null;
+ //$control->_stage=self::CS_CONSTRUCTED;
+ if(!($control->_flags & self::IS_ID_SET))
+ $control->_id='';
+ else
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
+ $control->clearCachedUniqueID(true);
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this instanceof INamingContainer)
+ $namingContainer=$this;
+ $page=$this->getPage();
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->_namingContainer=$namingContainer;
+ $control->_page=$page;
+ if($control->_id==='' && $namingContainer)
+ $control->generateAutomaticID();
+ $control->initRecursive($namingContainer);
+ }
+ }
+ }
+ if($this->_stage_stage=self::CS_CHILD_INITIALIZED;
+ if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
+ {
+ $page->applyControlSkin($this);
+ $this->_flags |= self::IS_SKIN_APPLIED;
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onInit(null);
+ else
+ $this->onInit(null);
+ $this->_stage=self::CS_INITIALIZED;
+ }
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function loadRecursive()
+ {
+ if($this->_stage_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onLoad(null);
+ else
+ $this->onLoad(null);
+ }
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->loadRecursive();
+ }
+ }
+ if($this->_stage_stage=self::CS_LOADED;
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function preRenderRecursive()
+ {
+ $this->autoDataBindProperties();
+
+ if($this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onPreRender(null);
+ else
+ $this->onPreRender(null);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
+ }
+ $this->addToPostDataLoader();
+ }
+ $this->_stage=self::CS_PRERENDERED;
+ }
+
+ /**
+ * Add controls implementing IPostBackDataHandler to post data loaders.
+ */
+ protected function addToPostDataLoader()
+ {
+ if($this instanceof IPostBackDataHandler)
+ $this->getPage()->registerPostDataLoader($this);
+ }
+
+ /**
+ * Performs the Unload step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function unloadRecursive()
+ {
+ if(!($this->_flags & self::IS_ID_SET))
+ $this->_id='';
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->unloadRecursive();
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onUnload(null);
+ else
+ $this->onUnload(null);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * The method raises 'OnInit' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->raiseEvent('OnInit',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * The method raises 'OnLoad' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->raiseEvent('OnLoad',$this,$param);
+ }
+
+ /**
+ * Raises 'OnDataBinding' event.
+ * This method is invoked when {@link dataBind} is invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onDataBinding($param)
+ {
+ Prado::trace("onDataBinding()",'System.Web.UI.TControl');
+ $this->raiseEvent('OnDataBinding',$this,$param);
+ }
+
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * The method raises 'OnUnload' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->raiseEvent('OnUnload',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * The method raises 'OnPreRender' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->raiseEvent('OnPreRender',$this,$param);
+ }
+
+ /**
+ * Invokes the parent's bubbleEvent method.
+ * A control who wants to bubble an event must call this method in its onEvent method.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameter
+ * @see bubbleEvent
+ */
+ protected function raiseBubbleEvent($sender,$param)
+ {
+ $control=$this;
+ while($control=$control->_parent)
+ {
+ if($control->bubbleEvent($sender,$param))
+ break;
+ }
+ }
+
+ /**
+ * This method responds to a bubbled event.
+ * This method should be overriden to provide customized response to a bubbled event.
+ * Check the type of event parameter to determine what event is bubbled currently.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameters
+ * @return boolean true if the event bubbling is handled and no more bubbling.
+ * @see raiseBubbleEvent
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ return false;
+ }
+
+ /**
+ * Broadcasts an event.
+ * The event will be sent to all controls on the current page hierarchy.
+ * If a control defines the event, the event will be raised for the control.
+ * If a control implements {@link IBroadcastEventReceiver}, its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
+ * be invoked which gives the control a chance to respond to the event.
+ * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
+ * event will have this event raised, and all controls implementing
+ * {@link IBroadcastEventReceiver} will also have its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
+ * invoked.
+ * @param string name of the broadcast event
+ * @param TControl sender of this event
+ * @param TEventParameter event parameter
+ */
+ public function broadcastEvent($name,$sender,$param)
+ {
+ $rootControl=(($page=$this->getPage())===null)?$this:$page;
+ $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
+ }
+
+ /**
+ * Recursively broadcasts an event.
+ * This method should only be used by framework developers.
+ * @param string name of the broadcast event
+ * @param TControl sender of the event
+ * @param TBroadcastEventParameter event parameter
+ */
+ private function broadcastEventInternal($name,$sender,$param)
+ {
+ if($this->hasEvent($name))
+ $this->raiseEvent($name,$sender,$param->getParameter());
+ if($this instanceof IBroadcastEventReceiver)
+ $this->broadcastEventReceived($sender,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->broadcastEventInternal($name,$sender,$param);
+ }
+ }
+ }
+
+ /**
+ * Traverse the whole control hierarchy rooted at this control.
+ * Callback function may be invoked for each control being visited.
+ * A pre-callback is invoked before traversing child controls;
+ * A post-callback is invoked after traversing child controls.
+ * Callback functions can be global functions or class methods.
+ * They must be of the following signature:
+ *
+ * function callback_func($control,$param) {...}
+ *
+ * where $control refers to the control being visited and $param
+ * is the parameter that is passed originally when calling this traverse function.
+ *
+ * @param mixed parameter to be passed to callbacks for each control
+ * @param callback callback invoked before traversing child controls. If null, it is ignored.
+ * @param callback callback invoked after traversing child controls. If null, it is ignored.
+ */
+ protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
+ {
+ if($preCallback!==null)
+ call_user_func($preCallback,$this,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->traverseChildControls($param,$preCallback,$postCallback);
+ }
+ }
+ }
+ if($postCallback!==null)
+ call_user_func($postCallback,$this,$param);
+ }
+
+ /**
+ * Renders the control.
+ * Only when the control is visible will the control be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderControl($writer)
+ {
+ if($this instanceof IActiveControl || $this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->render($writer);
+ else
+ $this->render($writer);
+ }
+ }
+
+ /**
+ * Renders the control.
+ * This method is invoked by {@link renderControl} when the control is visible.
+ * You can override this method to provide customized rendering of the control.
+ * By default, the control simply renders all its child contents.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderChildren($writer);
+ }
+
+ /**
+ * Renders the children of the control.
+ * This method iterates through all child controls and static text strings
+ * and renders them in order.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_string($control))
+ $writer->write($control);
+ else if($control instanceof TControl)
+ $control->renderControl($writer);
+ else if($control instanceof IRenderable)
+ $control->render($writer);
+ }
+ }
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ if(is_array($state))
+ {
+ // A null state means the stateful properties all take default values.
+ // So if the state is enabled, we have to assign the null value.
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if(isset($state[1]))
+ {
+ $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
+ unset($state[1]);
+ }
+ else
+ unset($this->_rf[self::RF_CONTROLSTATE]);
+ if($needViewState)
+ {
+ if(isset($state[0]))
+ $this->_viewState=&$state[0];
+ else
+ $this->_viewState=array();
+ }
+ unset($state[0]);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if(isset($state[$control->_id]))
+ {
+ $control->loadStateRecursive($state[$control->_id],$needViewState);
+ unset($state[$control->_id]);
+ }
+ }
+ }
+ }
+ if(!empty($state))
+ $this->_rf[self::RF_CHILD_STATE]=&$state;
+ }
+ $this->_stage=self::CS_STATE_LOADED;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->loadState();
+ else
+ $this->loadState();
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->saveState();
+ else
+ $this->saveState();
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ $state=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $state[$control->_id]=&$control->saveStateRecursive($needViewState);
+ }
+ }
+ if($needViewState && !empty($this->_viewState))
+ $state[0]=&$this->_viewState;
+ if(isset($this->_rf[self::RF_CONTROLSTATE]))
+ $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
+ return $state;
+ }
+
+ /**
+ * Applies a stylesheet skin to a control.
+ * @param TPage the page containing the control
+ * @throws TInvalidOperationException if the stylesheet skin is applied already
+ */
+ public function applyStyleSheetSkin($page)
+ {
+ if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
+ {
+ $page->applyControlStyleSheet($this);
+ $this->_flags |= self::IS_STYLESHEET_APPLIED;
+ }
+ else if($this->_flags & self::IS_STYLESHEET_APPLIED)
+ throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
+ }
+
+ /**
+ * Clears the cached UniqueID.
+ * If $recursive=true, all children's cached UniqueID will be cleared as well.
+ * @param boolean whether the clearing is recursive.
+ */
+ private function clearCachedUniqueID($recursive)
+ {
+ if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->clearCachedUniqueID($recursive);
+ }
+ $this->_uid=null;
+ }
+
+ /**
+ * Generates an automatic ID for the control.
+ */
+ private function generateAutomaticID()
+ {
+ $this->_flags &= ~self::IS_ID_SET;
+ if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
+ $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
+ $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
+ $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Clears the list of the controls whose IDs are managed by the specified naming container.
+ */
+ private function clearNameTable()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS]);
+ }
+
+ /**
+ * Updates the list of the controls whose IDs are managed by the specified naming container.
+ * @param TControl the naming container
+ * @param TControlCollection list of controls
+ * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
+ */
+ private function fillNameTable($container,$controls)
+ {
+ foreach($controls as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id!=='')
+ {
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
+ throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
+ else
+ $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
+ }
+ if(!($control instanceof INamingContainer) && $control->getHasControls())
+ $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
+ }
+ }
+ }
+}
+
+
+/**
+ * TControlCollection class
+ *
+ * TControlCollection implements a collection that enables
+ * controls to maintain a list of their child controls.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ * @param boolean whether the list is read-only
+ */
+ public function __construct(TControl $owner,$readOnly=false)
+ {
+ $this->_o=$owner;
+ parent::__construct(null,$readOnly);
+ }
+
+ /**
+ * @return TControl the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added child control.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ {
+ parent::insertAt($index,$item);
+ $this->_o->addedControl($item);
+ }
+ else if(is_string($item) || ($item instanceof IRenderable))
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('controlcollection_control_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * cleanup work when removing a child control.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TControl)
+ $this->_o->removedControl($item);
+ return $item;
+ }
+
+ /**
+ * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer}
+ */
+ public function clear()
+ {
+ parent::clear();
+ if($this->_o instanceof INamingContainer)
+ $this->_o->clearNamingContainer();
+ }
+}
+
+/**
+ * TEmptyControlCollection class
+ *
+ * TEmptyControlCollection implements an empty control list that prohibits adding
+ * controls to it. This is useful for controls that do not allow child controls.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TEmptyControlCollection extends TControlCollection
+{
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ */
+ public function __construct(TControl $owner)
+ {
+ parent::__construct($owner,true);
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by ignoring new addition.
+ * @param integer the speicified position.
+ * @param mixed new item
+ */
+ public function insertAt($index,$item)
+ {
+ if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case
+ parent::insertAt($index,$item); // this will generate an exception in parent implementation
+ }
+}
+
+/**
+ * INamingContainer interface.
+ * INamingContainer marks a control as a naming container.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface INamingContainer
+{
+}
+
+/**
+ * IPostBackEventHandler interface
+ *
+ * If a control wants to respond to postback event, it must implement this interface.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackEventHandler
+{
+ /**
+ * Raises postback event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand)
+ * indicating the component is responsible for the postback event.
+ * @param string the parameter associated with the postback event
+ */
+ public function raisePostBackEvent($param);
+}
+
+/**
+ * IPostBackDataHandler interface
+ *
+ * If a control wants to load post data, it must implement this interface.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackDataHandler
+{
+ /**
+ * Loads user input data.
+ * The implementation of this function can use $values[$key] to get the user input
+ * data that are meant for the particular control.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values);
+ /**
+ * Raises postdata changed event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged)
+ * indicating the control data is changed.
+ */
+ public function raisePostDataChangedEvent();
+ /**
+ * @return boolean whether postback causes the data change. Defaults to false for non-postback state.
+ */
+ public function getDataChanged();
+}
+
+
+/**
+ * IValidator interface
+ *
+ * If a control wants to validate user input, it must implement this interface.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidator
+{
+ /**
+ * Validates certain data.
+ * The implementation of this function should validate certain data
+ * (e.g. data entered into TTextBox control).
+ * @return boolean whether the data passes the validation
+ */
+ public function validate();
+ /**
+ * @return boolean whether the previous {@link validate()} is successful.
+ */
+ public function getIsValid();
+ /**
+ * @param boolean whether the validator validates successfully
+ */
+ public function setIsValid($value);
+ /**
+ * @return string error message during last validate
+ */
+ public function getErrorMessage();
+ /**
+ * @param string error message for the validation
+ */
+ public function setErrorMessage($value);
+}
+
+
+/**
+ * IValidatable interface
+ *
+ * If a control wants to be validated by a validator, it must implement this interface.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidatable
+{
+ /**
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue();
+ /**
+ * @return boolean wether this control's validators validated successfully (must default to true)
+ */
+ public function getIsValid();
+ /**
+ * @return boolean wether this control's validators validated successfully
+ */
+ public function setIsValid($value);
+}
+
+/**
+ * IBroadcastEventReceiver interface
+ *
+ * If a control wants to check broadcast event, it must implement this interface.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IBroadcastEventReceiver
+{
+ /**
+ * Handles broadcast event.
+ * This method is invoked automatically when an event is broadcasted.
+ * Within this method, you may check the event name given in
+ * the event parameter to determine whether you should respond to
+ * this event.
+ * @param TControl sender of the event
+ * @param TBroadCastEventParameter event parameter
+ */
+ public function broadcastEventReceived($sender,$param);
+}
+
+/**
+ * ITheme interface.
+ *
+ * This interface must be implemented by theme.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITheme
+{
+ /**
+ * Applies this theme to the specified control.
+ * @param TControl the control to be applied with this theme
+ */
+ public function applySkin($control);
+}
+
+/**
+ * ITemplate interface
+ *
+ * ITemplate specifies the interface for classes encapsulating
+ * parsed template structures.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITemplate
+{
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the parent control
+ */
+ public function instantiateIn($parent);
+}
+
+/**
+ * IButtonControl interface
+ *
+ * IButtonControl specifies the common properties and events that must
+ * be implemented by a button control, such as {@link TButton}, {@link TLinkButton},
+ * {@link TImageButton}.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IButtonControl
+{
+ /**
+ * @return string caption of the button
+ */
+ public function getText();
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value);
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation
+ */
+ public function getCausesValidation();
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value);
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName();
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value);
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter();
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value);
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup();
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value);
+
+ /**
+ * Raises OnClick event.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param);
+
+ /**
+ * Raises OnCommand event.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param);
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value);
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton();
+}
+
+/**
+ * ISurroundable interface
+ *
+ * Identifies controls that may create an additional surrounding tag. The id of the
+ * tag can be obtained with {@link getSurroundingTagID}.
+ *
+ * @package System.Web.UI
+ * @since 3.1.2
+ */
+interface ISurroundable
+{
+ /**
+ * @return string the id of the embedding tag of the control or the control's clientID if not surrounded
+ */
+ public function getSurroundingTagID();
+}
+
+/**
+ * TBroadcastEventParameter class
+ *
+ * TBroadcastEventParameter encapsulates the parameter data for
+ * events that are broadcasted. The name of of the event is specified via
+ * {@link setName Name} property while the event parameter is via
+ * {@link setParameter Parameter} property.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TBroadcastEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the broadcast event
+ * @param mixed parameter of the broadcast event
+ */
+ public function __construct($name='',$parameter=null)
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the broadcast event
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name of the broadcast event
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return mixed parameter of the broadcast event
+ */
+ public function getParameter()
+ {
+ return $this->_param;
+ }
+
+ /**
+ * @param mixed parameter of the broadcast event
+ */
+ public function setParameter($value)
+ {
+ $this->_param=$value;
+ }
+}
+
+/**
+ * TCommandEventParameter class
+ *
+ * TCommandEventParameter encapsulates the parameter data for Command
+ * event of button controls. You can access the name of the command via
+ * {@link getCommandName CommandName} property, and the parameter carried
+ * with the command via {@link getCommandParameter CommandParameter} property.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCommandEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the command
+ * @param string parameter of the command
+ */
+ public function __construct($name='',$parameter='')
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the command
+ */
+ public function getCommandName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return string parameter of the command
+ */
+ public function getCommandParameter()
+ {
+ return $this->_param;
+ }
+}
+
+
+/**
+ * TCompositeLiteral class
+ *
+ * TCompositeLiteral is used internally by {@link TTemplate} for representing
+ * consecutive static strings, expressions and statements.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+
+ /**
+ * Constructor.
+ * @param array list of items to be represented by TCompositeLiteral
+ */
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+
+ /**
+ * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+
+ /**
+ * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+
+ /**
+ * Evaluates the expressions and/or statements in the component.
+ */
+ public function evaluateDynamicContent()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ }
+
+ /**
+ * Performs databindings.
+ * This method is required by {@link IBindable}
+ */
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+
+?>
diff --git a/framework/Web/UI/TControlAdapter.php b/framework/Web/UI/TControlAdapter.php
index 5f06c360..a1afd353 100644
--- a/framework/Web/UI/TControlAdapter.php
+++ b/framework/Web/UI/TControlAdapter.php
@@ -1,143 +1,143 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TControlAdapter class
- *
- * TControlAdapter is the base class for adapters that customize
- * various behaviors for the control to which the adapter is attached.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControlAdapter extends TApplicationComponent
-{
- /**
- * @var TControl the control to which the adapter is attached
- */
- protected $_control;
-
- /**
- * Constructor.
- * @param TControl the control to which the adapter is attached
- */
- public function __construct($control)
- {
- $this->_control=$control;
- }
-
- /**
- * @return TControl the control to which this adapter is attached
- */
- public function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @return TPage the page that contains the attached control
- */
- public function getPage()
- {
- return $this->_control?$this->_control->getPage():null;
- }
-
- /**
- * Creates child controls for the attached control.
- * Default implementation calls the attached control's corresponding method.
- */
- public function createChildControls()
- {
- $this->_control->createChildControls();
- }
-
- /**
- * Loads additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function loadState()
- {
- $this->_control->loadState();
- }
-
- /**
- * Saves additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function saveState()
- {
- $this->_control->saveState();
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->_control->onInit($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->_control->onLoad($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->_control->onPreRender($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->_control->onUnload($param);
- }
-
- /**
- * This method is invoked when the control renders itself.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- $this->_control->render($writer);
- }
-
- /**
- * Renders the control's children.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderChildren($writer)
- {
- $this->_control->renderChildren($writer);
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TControlAdapter class
+ *
+ * TControlAdapter is the base class for adapters that customize
+ * various behaviors for the control to which the adapter is attached.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlAdapter extends TApplicationComponent
+{
+ /**
+ * @var TControl the control to which the adapter is attached
+ */
+ protected $_control;
+
+ /**
+ * Constructor.
+ * @param TControl the control to which the adapter is attached
+ */
+ public function __construct($control)
+ {
+ $this->_control=$control;
+ }
+
+ /**
+ * @return TControl the control to which this adapter is attached
+ */
+ public function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @return TPage the page that contains the attached control
+ */
+ public function getPage()
+ {
+ return $this->_control?$this->_control->getPage():null;
+ }
+
+ /**
+ * Creates child controls for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function createChildControls()
+ {
+ $this->_control->createChildControls();
+ }
+
+ /**
+ * Loads additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function loadState()
+ {
+ $this->_control->loadState();
+ }
+
+ /**
+ * Saves additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function saveState()
+ {
+ $this->_control->saveState();
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->_control->onInit($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->_control->onLoad($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->_control->onPreRender($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->_control->onUnload($param);
+ }
+
+ /**
+ * This method is invoked when the control renders itself.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->_control->render($writer);
+ }
+
+ /**
+ * Renders the control's children.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ $this->_control->renderChildren($writer);
+ }
+}
+
diff --git a/framework/Web/UI/TForm.php b/framework/Web/UI/TForm.php
index f57f7482..2d60a4e4 100644
--- a/framework/Web/UI/TForm.php
+++ b/framework/Web/UI/TForm.php
@@ -1,171 +1,171 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TForm class
- *
- * TForm displays an HTML form. Besides regular body content,
- * it displays hidden fields, javascript blocks and files that are registered
- * through {@link TClientScriptManager}.
- *
- * A TForm is required for a page that needs postback.
- * Each page can contain at most one TForm. If multiple HTML forms are needed,
- * please use regular HTML form tags for those forms that post to different
- * URLs.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TForm extends TControl
-{
- /**
- * Registers the form with the page.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setForm($this);
- }
-
- /**
- * Adds form specific attributes to renderer.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $writer->addAttribute('method',$this->getMethod());
- $uri=$this->getRequest()->getRequestURI();
- $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri)));
- if(($enctype=$this->getEnctype())!=='')
- $writer->addAttribute('enctype',$enctype);
-
- $attributes=$this->getAttributes();
- $attributes->remove('action');
- $writer->addAttributes($attributes);
-
- if(($butt=$this->getDefaultButton())!=='')
- {
- if(($button=$this->findControl($butt))!==null)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- else
- throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
- }
- }
-
- /**
- * Renders the form.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- $page=$this->getPage();
-
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag('form');
-
- $cs=$page->getClientScript();
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHiddenFieldsBegin($writer);
- $cs->renderScriptFilesBegin($writer);
- $cs->renderBeginScripts($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $cs->renderHiddenFieldsEnd($writer);
- $page->endFormRender($writer);
-
- $cs->renderScriptFilesEnd($writer);
- $cs->renderEndScripts($writer);
- }
- else
- {
- $cs->renderHiddenFieldsBegin($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $page->endFormRender($writer);
-
- $cs->renderHiddenFieldsEnd($writer);
- }
-
- $writer->renderEndTag();
- }
-
- /**
- * @return string id path to the default button control.
- */
- public function getDefaultButton()
- {
- return $this->getViewState('DefaultButton','');
- }
-
- /**
- * Sets a button to be default one in a form.
- * A default button will be clicked if a user presses 'Enter' key within
- * the form.
- * @param string id path to the default button control.
- */
- public function setDefaultButton($value)
- {
- $this->setViewState('DefaultButton',$value,'');
- }
-
- /**
- * @return string form submission method. Defaults to 'post'.
- */
- public function getMethod()
- {
- return $this->getViewState('Method','post');
- }
-
- /**
- * @param string form submission method. Valid values include 'post' and 'get'.
- */
- public function setMethod($value)
- {
- $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
- }
-
- /**
- * @return string the encoding type a browser uses to post data back to the server
- */
- public function getEnctype()
- {
- return $this->getViewState('Enctype','');
- }
-
- /**
- * @param string the encoding type a browser uses to post data back to the server.
- * Commonly used types include
- * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
- * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
- * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
- */
- public function setEnctype($value)
- {
- $this->setViewState('Enctype',$value,'');
- }
-
- /**
- * @return string form name, which is equal to {@link getUniqueID UniqueID}.
- */
- public function getName()
- {
- return $this->getUniqueID();
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TForm class
+ *
+ * TForm displays an HTML form. Besides regular body content,
+ * it displays hidden fields, javascript blocks and files that are registered
+ * through {@link TClientScriptManager}.
+ *
+ * A TForm is required for a page that needs postback.
+ * Each page can contain at most one TForm. If multiple HTML forms are needed,
+ * please use regular HTML form tags for those forms that post to different
+ * URLs.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TForm extends TControl
+{
+ /**
+ * Registers the form with the page.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setForm($this);
+ }
+
+ /**
+ * Adds form specific attributes to renderer.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $writer->addAttribute('method',$this->getMethod());
+ $uri=$this->getRequest()->getRequestURI();
+ $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri)));
+ if(($enctype=$this->getEnctype())!=='')
+ $writer->addAttribute('enctype',$enctype);
+
+ $attributes=$this->getAttributes();
+ $attributes->remove('action');
+ $writer->addAttributes($attributes);
+
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ if(($button=$this->findControl($butt))!==null)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ else
+ throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
+ }
+ }
+
+ /**
+ * Renders the form.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag('form');
+
+ $cs=$page->getClientScript();
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+ $cs->renderScriptFilesBegin($writer);
+ $cs->renderBeginScripts($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderScriptFilesEnd($writer);
+ $cs->renderEndScripts($writer);
+ }
+ else
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderHiddenFieldsEnd($writer);
+ }
+
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return string id path to the default button control.
+ */
+ public function getDefaultButton()
+ {
+ return $this->getViewState('DefaultButton','');
+ }
+
+ /**
+ * Sets a button to be default one in a form.
+ * A default button will be clicked if a user presses 'Enter' key within
+ * the form.
+ * @param string id path to the default button control.
+ */
+ public function setDefaultButton($value)
+ {
+ $this->setViewState('DefaultButton',$value,'');
+ }
+
+ /**
+ * @return string form submission method. Defaults to 'post'.
+ */
+ public function getMethod()
+ {
+ return $this->getViewState('Method','post');
+ }
+
+ /**
+ * @param string form submission method. Valid values include 'post' and 'get'.
+ */
+ public function setMethod($value)
+ {
+ $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
+ }
+
+ /**
+ * @return string the encoding type a browser uses to post data back to the server
+ */
+ public function getEnctype()
+ {
+ return $this->getViewState('Enctype','');
+ }
+
+ /**
+ * @param string the encoding type a browser uses to post data back to the server.
+ * Commonly used types include
+ * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
+ * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
+ * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
+ */
+ public function setEnctype($value)
+ {
+ $this->setViewState('Enctype',$value,'');
+ }
+
+ /**
+ * @return string form name, which is equal to {@link getUniqueID UniqueID}.
+ */
+ public function getName()
+ {
+ return $this->getUniqueID();
+ }
+}
+
diff --git a/framework/Web/UI/THtmlWriter.php b/framework/Web/UI/THtmlWriter.php
index 96e1a5e1..9e264c77 100644
--- a/framework/Web/UI/THtmlWriter.php
+++ b/framework/Web/UI/THtmlWriter.php
@@ -1,229 +1,229 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THtmlWriter class
- *
- * THtmlWriter is a writer that renders valid XHTML outputs.
- * It provides functions to render tags, their attributes and stylesheet fields.
- * Attribute and stylesheet values will be automatically HTML-encoded if
- * they require so. For example, the 'value' attribute in an input tag
- * will be encoded.
- *
- * A common usage of THtmlWriter is as the following sequence:
- *
- * $writer->addAttribute($name1,$value1);
- * $writer->addAttribute($name2,$value2);
- * $writer->renderBeginTag($tagName);
- * // ... render contents enclosed within the tag here
- * $writer->renderEndTag();
- *
- * Make sure each invocation of {@link renderBeginTag} is accompanied with
- * a {@link renderEndTag} and they are properly nested, like nesting
- * tags in HTML and XHTML.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THtmlWriter extends TApplicationComponent implements ITextWriter
-{
- /**
- * @var array list of tags are do not need a closing tag
- */
- private static $_simpleTags=array(
- 'area'=>true,
- 'base'=>true,
- 'basefont'=>true,
- 'bgsound'=>true,
- 'col'=>true,
- 'embed'=>true,
- 'frame'=>true,
- 'hr'=>true,
- 'img'=>true,
- 'input'=>true,
- 'isindex'=>true,
- 'link'=>true,
- 'meta'=>true,
- 'wbr'=>true,
- );
- /**
- * @var array list of attributes to be rendered for a tag
- */
- private $_attributes=array();
- /**
- * @var array list of openning tags
- */
- private $_openTags=array();
- /**
- * @var array list of style attributes
- */
- private $_styles=array();
- /**
- * @var ITextWriter writer
- */
- private $_writer=null;
-
- /**
- * Constructor.
- * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
- */
- public function __construct($writer)
- {
- $this->_writer=$writer;
- }
-
- public function getWriter()
- {
- return $this->_writer;
- }
-
- public function setWriter($writer)
- {
- $this->_writer = $writer;
- }
- /**
- * Adds a list of attributes to be rendered.
- * @param array list of attributes to be rendered
- */
- public function addAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds an attribute to be rendered.
- * @param string name of the attribute
- * @param string value of the attribute
- */
- public function addAttribute($name,$value)
- {
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named attribute from rendering
- * @param string name of the attribute to be removed
- */
- public function removeAttribute($name)
- {
- unset($this->_attributes[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Adds a list of stylesheet attributes to be rendered.
- * @param array list of stylesheet attributes to be rendered
- */
- public function addStyleAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds a stylesheet attribute to be rendered
- * @param string stylesheet attribute name
- * @param string stylesheet attribute value
- */
- public function addStyleAttribute($name,$value)
- {
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named stylesheet attribute from rendering
- * @param string name of the stylesheet attribute to be removed
- */
- public function removeStyleAttribute($name)
- {
- unset($this->_styles[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Flushes the rendering result.
- * This will invoke the underlying writer's flush method.
- * @return string the content being flushed
- */
- public function flush()
- {
- return $this->_writer->flush();
- }
-
- /**
- * Renders a string.
- * @param string string to be rendered
- */
- public function write($str)
- {
- $this->_writer->write($str);
- }
-
- /**
- * Renders a string and appends a newline to it.
- * @param string string to be rendered
- */
- public function writeLine($str='')
- {
- $this->_writer->write($str."\n");
- }
-
- /**
- * Renders an HTML break.
- */
- public function writeBreak()
- {
- $this->_writer->write(' ');
- }
-
- /**
- * Renders the openning tag.
- * @param string tag name
- */
- public function renderBeginTag($tagName)
- {
- $str='<'.$tagName;
- foreach($this->_attributes as $name=>$value)
- $str.=' '.$name.'="'.$value.'"';
- if(!empty($this->_styles))
- {
- $str.=' style="';
- foreach($this->_styles as $name=>$value)
- $str.=$name.':'.$value.';';
- $str.='"';
- }
- if(isset(self::$_simpleTags[$tagName]))
- {
- $str.=' />';
- $this->_openTags[] = '';
- }
- else
- {
- $str.='>';
- $this->_openTags[] = $tagName;
- }
- $this->_writer->write($str);
- $this->_attributes=array();
- $this->_styles=array();
- }
-
- /**
- * Renders the closing tag.
- */
- public function renderEndTag()
- {
- if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
- $this->_writer->write(''.$tagName.'>');
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * THtmlWriter class
+ *
+ * THtmlWriter is a writer that renders valid XHTML outputs.
+ * It provides functions to render tags, their attributes and stylesheet fields.
+ * Attribute and stylesheet values will be automatically HTML-encoded if
+ * they require so. For example, the 'value' attribute in an input tag
+ * will be encoded.
+ *
+ * A common usage of THtmlWriter is as the following sequence:
+ *
+ * $writer->addAttribute($name1,$value1);
+ * $writer->addAttribute($name2,$value2);
+ * $writer->renderBeginTag($tagName);
+ * // ... render contents enclosed within the tag here
+ * $writer->renderEndTag();
+ *
+ * Make sure each invocation of {@link renderBeginTag} is accompanied with
+ * a {@link renderEndTag} and they are properly nested, like nesting
+ * tags in HTML and XHTML.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THtmlWriter extends TApplicationComponent implements ITextWriter
+{
+ /**
+ * @var array list of tags are do not need a closing tag
+ */
+ private static $_simpleTags=array(
+ 'area'=>true,
+ 'base'=>true,
+ 'basefont'=>true,
+ 'bgsound'=>true,
+ 'col'=>true,
+ 'embed'=>true,
+ 'frame'=>true,
+ 'hr'=>true,
+ 'img'=>true,
+ 'input'=>true,
+ 'isindex'=>true,
+ 'link'=>true,
+ 'meta'=>true,
+ 'wbr'=>true,
+ );
+ /**
+ * @var array list of attributes to be rendered for a tag
+ */
+ private $_attributes=array();
+ /**
+ * @var array list of openning tags
+ */
+ private $_openTags=array();
+ /**
+ * @var array list of style attributes
+ */
+ private $_styles=array();
+ /**
+ * @var ITextWriter writer
+ */
+ private $_writer=null;
+
+ /**
+ * Constructor.
+ * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
+ */
+ public function __construct($writer)
+ {
+ $this->_writer=$writer;
+ }
+
+ public function getWriter()
+ {
+ return $this->_writer;
+ }
+
+ public function setWriter($writer)
+ {
+ $this->_writer = $writer;
+ }
+ /**
+ * Adds a list of attributes to be rendered.
+ * @param array list of attributes to be rendered
+ */
+ public function addAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds an attribute to be rendered.
+ * @param string name of the attribute
+ * @param string value of the attribute
+ */
+ public function addAttribute($name,$value)
+ {
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named attribute from rendering
+ * @param string name of the attribute to be removed
+ */
+ public function removeAttribute($name)
+ {
+ unset($this->_attributes[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Adds a list of stylesheet attributes to be rendered.
+ * @param array list of stylesheet attributes to be rendered
+ */
+ public function addStyleAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds a stylesheet attribute to be rendered
+ * @param string stylesheet attribute name
+ * @param string stylesheet attribute value
+ */
+ public function addStyleAttribute($name,$value)
+ {
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named stylesheet attribute from rendering
+ * @param string name of the stylesheet attribute to be removed
+ */
+ public function removeStyleAttribute($name)
+ {
+ unset($this->_styles[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Flushes the rendering result.
+ * This will invoke the underlying writer's flush method.
+ * @return string the content being flushed
+ */
+ public function flush()
+ {
+ return $this->_writer->flush();
+ }
+
+ /**
+ * Renders a string.
+ * @param string string to be rendered
+ */
+ public function write($str)
+ {
+ $this->_writer->write($str);
+ }
+
+ /**
+ * Renders a string and appends a newline to it.
+ * @param string string to be rendered
+ */
+ public function writeLine($str='')
+ {
+ $this->_writer->write($str."\n");
+ }
+
+ /**
+ * Renders an HTML break.
+ */
+ public function writeBreak()
+ {
+ $this->_writer->write(' ');
+ }
+
+ /**
+ * Renders the openning tag.
+ * @param string tag name
+ */
+ public function renderBeginTag($tagName)
+ {
+ $str='<'.$tagName;
+ foreach($this->_attributes as $name=>$value)
+ $str.=' '.$name.'="'.$value.'"';
+ if(!empty($this->_styles))
+ {
+ $str.=' style="';
+ foreach($this->_styles as $name=>$value)
+ $str.=$name.':'.$value.';';
+ $str.='"';
+ }
+ if(isset(self::$_simpleTags[$tagName]))
+ {
+ $str.=' />';
+ $this->_openTags[] = '';
+ }
+ else
+ {
+ $str.='>';
+ $this->_openTags[] = $tagName;
+ }
+ $this->_writer->write($str);
+ $this->_attributes=array();
+ $this->_styles=array();
+ }
+
+ /**
+ * Renders the closing tag.
+ */
+ public function renderEndTag()
+ {
+ if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
+ $this->_writer->write(''.$tagName.'>');
+ }
+}
+
diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php
index 37326031..26a06b64 100644
--- a/framework/Web/UI/TPage.php
+++ b/framework/Web/UI/TPage.php
@@ -1,1341 +1,1341 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-Prado::using('System.Web.UI.WebControls.*');
-Prado::using('System.Web.UI.TControl');
-Prado::using('System.Web.UI.WebControls.TWebControl');
-Prado::using('System.Web.UI.TCompositeControl');
-Prado::using('System.Web.UI.TTemplateControl');
-Prado::using('System.Web.UI.TForm');
-Prado::using('System.Web.UI.TClientScriptManager');
-
-/**
- * TPage class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TPage extends TTemplateControl
-{
- /**
- * system post fields
- */
- const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
- const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
- const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
- const FIELD_PAGESTATE='PRADO_PAGESTATE';
- const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
- const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
-
- /**
- * @var array system post fields
- */
- private static $_systemPostFields=array(
- 'PRADO_POSTBACK_TARGET'=>true,
- 'PRADO_POSTBACK_PARAMETER'=>true,
- 'PRADO_LASTFOCUS'=>true,
- 'PRADO_PAGESTATE'=>true,
- 'PRADO_CALLBACK_TARGET'=>true,
- 'PRADO_CALLBACK_PARAMETER'=>true
- );
- /**
- * @var TForm form instance
- */
- private $_form;
- /**
- * @var THead head instance
- */
- private $_head;
- /**
- * @var array list of registered validators
- */
- private $_validators=array();
- /**
- * @var boolean if validation has been performed
- */
- private $_validated=false;
- /**
- * @var TTheme page theme
- */
- private $_theme;
- /**
- * @var string page title set when Head is not in page yet
- */
- private $_title;
- /**
- * @var TTheme page stylesheet theme
- */
- private $_styleSheet;
- /**
- * @var TClientScriptManager client script manager
- */
- private $_clientScript;
- /**
- * @var TMap data post back by user
- */
- protected $_postData;
- /**
- * @var TMap postback data that is not handled during first invocation of LoadPostData.
- */
- protected $_restPostData;
- /**
- * @var array list of controls whose data have been changed due to the postback
- */
- protected $_controlsPostDataChanged=array();
- /**
- * @var array list of controls that need to load post data in the current request
- */
- protected $_controlsRequiringPostData=array();
- /**
- * @var array list of controls that need to load post data in the next postback
- */
- protected $_controlsRegisteredForPostData=array();
- /**
- * @var TControl control that needs to raise postback event
- */
- private $_postBackEventTarget;
- /**
- * @var string postback event parameter
- */
- private $_postBackEventParameter;
- /**
- * @var boolean whether the form has been rendered
- */
- protected $_formRendered=false;
- /**
- * @var boolean whether the current rendering is within a form
- */
- protected $_inFormRender=false;
- /**
- * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
- */
- private $_focus;
- /**
- * @var string page path to this page
- */
- private $_pagePath='';
- /**
- * @var boolean whether page state should be HMAC validated
- */
- private $_enableStateValidation=true;
- /**
- * @var boolean whether page state should be encrypted
- */
- private $_enableStateEncryption=false;
- /**
- * @var boolean whether page state should be compressed
- * @since 3.1.6
- */
- private $_enableStateCompression=true;
- /**
- * @var string page state persister class name
- */
- private $_statePersisterClass='System.Web.UI.TPageStatePersister';
- /**
- * @var mixed page state persister
- */
- private $_statePersister;
- /**
- * @var TStack stack used to store currently active caching controls
- */
- private $_cachingStack;
- /**
- * @var string state string to be stored on the client side
- */
- private $_clientState='';
- /**
- * @var array post data loader IDs.
- */
- protected $_postDataLoaders=array();
- /**
- * @var boolean true if loading post data.
- */
- protected $_isLoadingPostData=false;
- /**
- * @var boolean whether client supports javascript
- */
- private $_enableJavaScript=true;
- /**
- * @var THtmlWriter current html render writer
- */
- private $_writer;
-
- /**
- * Constructor.
- * Sets the page object to itself.
- * Derived classes must call parent implementation.
- */
- public function __construct()
- {
- $this->setPage($this);
- }
-
- /**
- * Runs through the page lifecycles.
- * @param THtmlTextWriter the HTML writer
- */
- public function run($writer)
- {
- Prado::trace("Running page life cycles",'System.Web.UI.TPage');
- $this->_writer = $writer;
-
- $this->determinePostBackMode();
-
- if($this->getIsPostBack())
- {
- if($this->getIsCallback())
- $this->processCallbackRequest($writer);
- else
- $this->processPostBackRequest($writer);
- }
- else
- $this->processNormalRequest($writer);
-
- $this->_writer = null;
- }
-
- protected function processNormalRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected function processPostBackRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected static function decodeUTF8($data, $enc)
- {
- if(is_array($data))
- {
- foreach($data as $k=>$v)
- $data[$k]=self::decodeUTF8($v, $enc);
- return $data;
- } elseif(is_string($data)) {
- return iconv('UTF-8',$enc.'//IGNORE',$data);
- } else {
- return $data;
- }
- }
-
- /**
- * Sets Adapter to TActivePageAdapter and calls apter to process the
- * callback request.
- */
- protected function processCallbackRequest($writer)
- {
- Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
-
- $this->setAdapter(new TActivePageAdapter($this));
-
- // Decode Callback postData from UTF-8 to current Charset
- if (($g=$this->getApplication()->getGlobalization(false))!==null &&
- strtoupper($enc=$g->getCharset())!='UTF-8')
- foreach ($this->_postData as $k=>$v)
- $this->_postData[$k]=self::decodeUTF8($v, $enc);
-
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
-
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
-
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
-
-
- $this->getAdapter()->processCallbackEvent($writer);
-
-/*
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
-*/
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
-/*
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
-*/
- $this->getAdapter()->renderCallbackResponse($writer);
-
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- /**
- * Gets the callback client script handler that allows javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript interface to client-side javascript code.
- */
- public function getCallbackClient()
- {
- if($this->getAdapter() !== null)
- return $this->getAdapter()->getCallbackClientHandler();
- else
- return new TCallbackClientScript();
- }
-
- /**
- * Set a new callback client handler.
- * @param TCallbackClientScript new callback client script handler.
- */
- public function setCallbackClient($client)
- {
- $this->getAdapter()->setCallbackClientHandler($client);
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- return $this->getAdapter()->getCallbackEventTarget();
- }
-
- /**
- * Registers a control to raise callback event in the current request.
- * @param TControl control registered to raise callback event.
- */
- public function setCallbackEventTarget(TControl $control)
- {
- $this->getAdapter()->setCallbackEventTarget($control);
- }
-
- /**
- * Callback parameter is decoded assuming JSON encoding.
- * @return string callback event parameter
- */
- public function getCallbackEventParameter()
- {
- return $this->getAdapter()->getCallbackEventParameter();
- }
-
- /**
- * @param mixed callback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->getAdapter()->setCallbackEventParameter($value);
- }
-
- /**
- * Register post data loaders for Callback to collect post data.
- * This method should only be called by framework developers.
- * @param TControl control that requires post data.
- * @see TControl::preRenderRecursive();
- */
- public function registerPostDataLoader($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_postDataLoaders[$id] = true;
- }
-
- /**
- * Get a list of IDs of controls that are enabled and require post data.
- * @return array list of IDs implementing IPostBackDataHandler
- */
- public function getPostDataLoaders()
- {
- return array_keys($this->_postDataLoaders);
- }
-
- /**
- * @return TForm the form on the page
- */
- public function getForm()
- {
- return $this->_form;
- }
-
- /**
- * Registers a TForm instance to the page.
- * Note, a page can contain at most one TForm instance.
- * @param TForm the form on the page
- * @throws TInvalidOperationException if this method is invoked twice or more.
- */
- public function setForm(TForm $form)
- {
- if($this->_form===null)
- $this->_form=$form;
- else
- throw new TInvalidOperationException('page_form_duplicated');
- }
-
- /**
- * Returns a list of registered validators.
- * If validation group is specified, only the validators in that group will be returned.
- * @param string validation group
- * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
- */
- public function getValidators($validationGroup=null)
- {
- if(!$this->_validators)
- $this->_validators=new TList;
- if(empty($validationGroup) === true)
- return $this->_validators;
- else
- {
- $list=new TList;
- foreach($this->_validators as $validator)
- if($validator->getValidationGroup()===$validationGroup)
- $list->add($validator);
- return $list;
- }
- }
-
- /**
- * Performs input validation.
- * This method will invoke the registered validators to perform the actual validation.
- * If validation group is specified, only the validators in that group will be invoked.
- * @param string validation group. If null, all validators will perform validation.
- */
- public function validate($validationGroup=null)
- {
- Prado::trace("Page validate()",'System.Web.UI.TPage');
- $this->_validated=true;
- if($this->_validators && $this->_validators->getCount())
- {
- if($validationGroup===null)
- {
- foreach($this->_validators as $validator)
- $validator->validate();
- }
- else
- {
- foreach($this->_validators as $validator)
- {
- if($validator->getValidationGroup()===$validationGroup)
- $validator->validate();
- }
- }
- }
- }
-
- /**
- * Returns whether user input is valid or not.
- * This method must be invoked after {@link validate} is called.
- * @return boolean whether the user input is valid or not.
- * @throws TInvalidOperationException if {@link validate} is not invoked yet.
- */
- public function getIsValid()
- {
- if($this->_validated)
- {
- if($this->_validators && $this->_validators->getCount())
- {
- foreach($this->_validators as $validator)
- if(!$validator->getIsValid())
- return false;
- }
- return true;
- }
- else
- throw new TInvalidOperationException('page_isvalid_unknown');
- }
-
- /**
- * @return TTheme the theme used for the page. Defaults to null.
- */
- public function getTheme()
- {
- if(is_string($this->_theme))
- $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
- return $this->_theme;
- }
-
- /**
- * Sets the theme to be used for the page.
- * @param string|TTheme the theme name or the theme object to be used for the page.
- */
- public function setTheme($value)
- {
- $this->_theme=empty($value)?null:$value;
- }
-
-
- /**
- * @return TTheme the stylesheet theme used for the page. Defaults to null.
- */
- public function getStyleSheetTheme()
- {
- if(is_string($this->_styleSheet))
- $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
- return $this->_styleSheet;
- }
-
- /**
- * Sets the stylesheet theme to be used for the page.
- * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
- */
- public function setStyleSheetTheme($value)
- {
- $this->_styleSheet=empty($value)?null:$value;
- }
-
- /**
- * Applies a skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied skin with
- */
- public function applyControlSkin($control)
- {
- if(($theme=$this->getTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * Applies a stylesheet skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied stylesheet skin with
- */
- public function applyControlStyleSheet($control)
- {
- if(($theme=$this->getStyleSheetTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * @return TClientScriptManager client script manager
- */
- public function getClientScript()
- {
- if(!$this->_clientScript) {
- $className = $classPath = $this->getService()->getClientScriptManagerClass();
- Prado::using($className);
- if(($pos=strrpos($className,'.'))!==false)
- $className=substr($className,$pos+1);
-
- if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
- throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
-
- $this->_clientScript=new $className($this);
- }
- return $this->_clientScript;
- }
-
- /**
- * Raises OnPreInit event.
- * This method is invoked right before {@link onInit OnInit} stage.
- * You may override this method to provide additional initialization that
- * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
- * {@link setStyleSheetTheme StyleSheetTheme}).
- * Remember to call the parent implementation to ensure OnPreInit event is raised.
- * @param mixed event parameter
- */
- public function onPreInit($param)
- {
- $this->raiseEvent('OnPreInit',$this,$param);
- }
-
- /**
- * Raises OnInitComplete event.
- * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional initialization that
- * should be done after {@link onInit OnInit}.
- * Remember to call the parent implementation to ensure OnInitComplete event is raised.
- * @param mixed event parameter
- */
- public function onInitComplete($param)
- {
- $this->raiseEvent('OnInitComplete',$this,$param);
- }
-
- /**
- * Raises OnPreLoad event.
- * This method is invoked right before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done before {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnPreLoad event is raised.
- * @param mixed event parameter
- */
- public function onPreLoad($param)
- {
- $this->raiseEvent('OnPreLoad',$this,$param);
- }
-
- /**
- * Raises OnLoadComplete event.
- * This method is invoked right after {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done after {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
- * @param mixed event parameter
- */
- public function onLoadComplete($param)
- {
- $this->raiseEvent('OnLoadComplete',$this,$param);
- }
-
- /**
- * Raises OnPreRenderComplete event.
- * This method is invoked right after {@link onPreRender OnPreRender} stage.
- * You may override this method to provide additional preparation for page rendering
- * that should be done after {@link onPreRender OnPreRender}.
- * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
- * @param mixed event parameter
- */
- public function onPreRenderComplete($param)
- {
- $this->raiseEvent('OnPreRenderComplete',$this,$param);
- $cs=$this->getClientScript();
- $theme=$this->getTheme();
- if($theme instanceof ITheme)
- {
- foreach($theme->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($theme->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
- $styleSheet=$this->getStyleSheetTheme();
- if($styleSheet instanceof ITheme)
- {
- foreach($styleSheet->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($styleSheet->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
-
- if($cs->getRequiresHead() && $this->getHead()===null)
- throw new TConfigurationException('page_head_required');
- }
-
- /**
- * Determines the media type of the CSS file.
- * The media type is determined according to the following file name pattern:
- * xxx.media-type.extension
- * For example, 'mystyle.print.css' means its media type is 'print'.
- * @param string CSS URL
- * @return string media type of the CSS file
- */
- private function getCssMediaType($url)
- {
- $segs=explode('.',basename($url));
- if(isset($segs[2]))
- return $segs[count($segs)-2];
- else
- return '';
- }
-
- /**
- * Raises OnSaveStateComplete event.
- * This method is invoked right after {@link onSaveState OnSaveState} stage.
- * You may override this method to provide additional logic after page state is saved.
- * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
- * @param mixed event parameter
- */
- public function onSaveStateComplete($param)
- {
- $this->raiseEvent('OnSaveStateComplete',$this,$param);
- }
-
- /**
- * Determines whether the current page request is a postback.
- * Call {@link getIsPostBack} to get the result.
- */
- private function determinePostBackMode()
- {
- $postData=$this->getRequest();
- if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
- $this->_postData=$postData;
- }
-
- /**
- * @return boolean whether the current page request is a postback
- */
- public function getIsPostBack()
- {
- return $this->_postData!==null;
- }
-
- /**
- * @return boolean whether this is a callback request
- */
- public function getIsCallback()
- {
- return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
- }
-
- /**
- * This method is invoked when control state is to be saved.
- * You can override this method to do last step state saving.
- * Parent implementation must be invoked.
- */
- public function saveState()
- {
- parent::saveState();
- $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
- }
-
- /**
- * This method is invoked right after the control has loaded its state.
- * You can override this method to initialize data from the control state.
- * Parent implementation must be invoked.
- */
- public function loadState()
- {
- parent::loadState();
- $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
- }
-
- /**
- * Loads page state from persistent storage.
- */
- protected function loadPageState()
- {
- Prado::trace("Loading state",'System.Web.UI.TPage');
- $state=$this->getStatePersister()->load();
- $this->loadStateRecursive($state,$this->getEnableViewState());
- }
-
- /**
- * Saves page state from persistent storage.
- */
- protected function savePageState()
- {
- Prado::trace("Saving state",'System.Web.UI.TPage');
- $state=&$this->saveStateRecursive($this->getEnableViewState());
- $this->getStatePersister()->save($state);
- }
-
- /**
- * @param string the field name
- * @return boolean whether the specified field is a system field in postback data
- */
- protected function isSystemPostField($field)
- {
- return isset(self::$_systemPostFields[$field]);
- }
-
- /**
- * Registers a control for loading post data in the next postback.
- * This method needs to be invoked if the control to load post data
- * may not have a post variable in some cases. For example, a checkbox,
- * if not checked, will not have a post value.
- * @param TControl control registered for loading post data
- */
- public function registerRequiresPostData($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_controlsRegisteredForPostData[$id]=true;
- $this->registerPostDataLoader($id);
- $params=func_get_args();
- foreach($this->getCachingStack() as $item)
- $item->registerAction('Page','registerRequiresPostData',array($id));
- }
-
- /**
- * @return TControl the control responsible for the current postback event, null if nonexistent
- */
- public function getPostBackEventTarget()
- {
- if($this->_postBackEventTarget===null && $this->_postData!==null)
- {
- $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
- if(!empty($eventTarget))
- $this->_postBackEventTarget=$this->findControl($eventTarget);
- }
- return $this->_postBackEventTarget;
- }
-
- /**
- * Registers a control to raise postback event in the current request.
- * @param TControl control registered to raise postback event.
- */
- public function setPostBackEventTarget(TControl $control)
- {
- $this->_postBackEventTarget=$control;
- }
-
- /**
- * @return string postback event parameter
- */
- public function getPostBackEventParameter()
- {
- if($this->_postBackEventParameter===null && $this->_postData!==null)
- {
- if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
- $this->_postBackEventParameter='';
- }
- return $this->_postBackEventParameter;
- }
-
- /**
- * @param string postback event parameter
- */
- public function setPostBackEventParameter($value)
- {
- $this->_postBackEventParameter=$value;
- }
-
- /**
- * Processes post data.
- * @param TMap post data to be processed
- * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
- */
- protected function processPostData($postData,$beforeLoad)
- {
- $this->_isLoadingPostData=true;
- if($beforeLoad)
- $this->_restPostData=new TMap;
- foreach($postData as $key=>$value)
- {
- if($this->isSystemPostField($key))
- continue;
- else if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else if($control instanceof IPostBackEventHandler &&
- empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
- {
- $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
- }
- unset($this->_controlsRequiringPostData[$key]);
- }
- else if($beforeLoad)
- $this->_restPostData->add($key,$value);
- }
-
- foreach($this->_controlsRequiringPostData as $key=>$value)
- {
- if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$this->_postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else
- throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
- unset($this->_controlsRequiringPostData[$key]);
- }
- }
- $this->_isLoadingPostData=false;
- }
-
- /**
- * @return boolean true if loading post data.
- */
- public function getIsLoadingPostData()
- {
- return $this->_isLoadingPostData;
- }
-
- /**
- * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
- */
- protected function raiseChangedEvents()
- {
- foreach($this->_controlsPostDataChanged as $control)
- $control->raisePostDataChangedEvent();
- }
-
- /**
- * Raises PostBack event.
- */
- protected function raisePostBackEvent()
- {
- if(($postBackHandler=$this->getPostBackEventTarget())===null)
- $this->validate();
- else if($postBackHandler instanceof IPostBackEventHandler)
- $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
- }
-
- /**
- * @return boolean Whether form rendering is in progress
- */
- public function getInFormRender()
- {
- return $this->_inFormRender;
- }
-
- /**
- * Ensures the control is rendered within a form.
- * @param TControl the control to be rendered
- * @throws TConfigurationException if the control is outside of the form
- */
- public function ensureRenderInForm($control)
- {
- if(!$this->getIsCallback() && !$this->_inFormRender)
- throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
- }
-
- /**
- * @internal This method is invoked by TForm at the beginning of its rendering
- */
- public function beginFormRender($writer)
- {
- if($this->_formRendered)
- throw new TConfigurationException('page_form_duplicated');
- $this->_formRendered=true;
- $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
- $this->_inFormRender=true;
- }
-
- /**
- * @internal This method is invoked by TForm at the end of its rendering
- */
- public function endFormRender($writer)
- {
- if($this->_focus)
- {
- if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
- $focus=$this->_focus->getClientID();
- else
- $focus=$this->_focus;
- $this->getClientScript()->registerFocusControl($focus);
- }
- else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
- $this->getClientScript()->registerFocusControl($lastFocus);
- $this->_inFormRender=false;
- }
-
- /**
- * Sets input focus on a control after the page is rendered to users.
- * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
- */
- public function setFocus($value)
- {
- $this->_focus=$value;
- }
-
- /**
- * @return boolean whether client supports javascript. Defaults to true.
- */
- public function getClientSupportsJavaScript()
- {
- return $this->_enableJavaScript;
- }
-
- /**
- * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
- */
- public function setClientSupportsJavaScript($value)
- {
- $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return THead page head, null if not available
- */
- public function getHead()
- {
- return $this->_head;
- }
-
- /**
- * @param THead page head
- * @throws TInvalidOperationException if a head already exists
- */
- public function setHead(THead $value)
- {
- if($this->_head)
- throw new TInvalidOperationException('page_head_duplicated');
- $this->_head=$value;
- if($this->_title!==null)
- {
- $this->_head->setTitle($this->_title);
- $this->_title=null;
- }
- }
-
- /**
- * @return string page title.
- */
- public function getTitle()
- {
- if($this->_head)
- return $this->_head->getTitle();
- else
- return $this->_title===null ? '' : $this->_title;
- }
-
- /**
- * Sets the page title.
- * Note, a {@link THead} control needs to place on the page
- * in order that this title be rendered.
- * @param string page title. This will override the title set in {@link getHead Head}.
- */
- public function setTitle($value)
- {
- if($this->_head)
- $this->_head->setTitle($value);
- else
- $this->_title=$value;
- }
-
- /**
- * Returns the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @return string the state to be stored on the client side
- */
- public function getClientState()
- {
- return $this->_clientState;
- }
-
- /**
- * Sets the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @param string the state to be stored on the client side
- */
- public function setClientState($state)
- {
- $this->_clientState=$state;
- }
-
- /**
- * @return string the state postback from client side
- */
- public function getRequestClientState()
- {
- return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
- }
-
- /**
- * @return string class name of the page state persister. Defaults to TPageStatePersister.
- */
- public function getStatePersisterClass()
- {
- return $this->_statePersisterClass;
- }
-
- /**
- * @param string class name of the page state persister.
- */
- public function setStatePersisterClass($value)
- {
- $this->_statePersisterClass=$value;
- }
-
- /**
- * @return IPageStatePersister page state persister
- */
- public function getStatePersister()
- {
- if($this->_statePersister===null)
- {
- $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
- if(!($this->_statePersister instanceof IPageStatePersister))
- throw new TInvalidDataTypeException('page_statepersister_invalid');
- $this->_statePersister->setPage($this);
- }
- return $this->_statePersister;
- }
-
- /**
- * @return boolean whether page state should be HMAC validated. Defaults to true.
- */
- public function getEnableStateValidation()
- {
- return $this->_enableStateValidation;
- }
-
- /**
- * @param boolean whether page state should be HMAC validated.
- */
- public function setEnableStateValidation($value)
- {
- $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be encrypted. Defaults to false.
- */
- public function getEnableStateEncryption()
- {
- return $this->_enableStateEncryption;
- }
-
- /**
- * @param boolean whether page state should be encrypted.
- */
- public function setEnableStateEncryption($value)
- {
- $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be compressed. Defaults to true.
- * @since 3.1.6
- */
- public function getEnableStateCompression()
- {
- return $this->_enableStateCompression;
- }
-
- /**
- * @param boolean whether page state should be compressed.
- * @since 3.1.6
- */
- public function setEnableStateCompression($value)
- {
- $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return string the requested page path for this page
- */
- public function getPagePath()
- {
- return $this->_pagePath;
- }
-
- /**
- * @param string the requested page path for this page
- */
- public function setPagePath($value)
- {
- $this->_pagePath=$value;
- }
-
- /**
- * Registers an action associated with the content being cached.
- * The registered action will be replayed if the content stored
- * in the cache is served to end-users.
- * @param string context of the action method. This is a property-path
- * referring to the context object (e.g. Page, Page.ClientScript).
- * @param string method name of the context object
- * @param array list of parameters to be passed to the action method
- */
- public function registerCachingAction($context,$funcName,$funcParams)
- {
- if($this->_cachingStack)
- {
- foreach($this->_cachingStack as $cache)
- $cache->registerAction($context,$funcName,$funcParams);
- }
- }
-
- /**
- * @return TStack stack of {@link TOutputCache} objects
- */
- public function getCachingStack()
- {
- if(!$this->_cachingStack)
- $this->_cachingStack=new TStack;
- return $this->_cachingStack;
- }
-
- /**
- * Flushes output
- */
- public function flushWriter()
- {
- if ($this->_writer)
- $this->Response->write($this->_writer->flush());
- }
-}
-
-/**
- * IPageStatePersister interface.
- *
- * IPageStatePersister interface is required for all page state persister
- * classes.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1
- */
-interface IPageStatePersister
-{
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage();
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page);
- /**
- * Saves state to persistent storage.
- * @param mixed state to be stored
- */
- public function save($state);
- /**
- * Loads page state from persistent storage
- * @return mixed the restored state
- */
- public function load();
-}
-
-
-/**
- * TPageStateFormatter class.
- *
- * TPageStateFormatter is a utility class to transform the page state
- * into and from a string that can be properly saved in persistent storage.
- *
- * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
- * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
- * TPageStateFormatter may do HMAC validation and encryption to prevent
- * the state data from being tampered or viewed.
- * The private keys and hashing/encryption methods are determined by
- * {@link TApplication::getSecurityManager() SecurityManager}.
- *
- * @author Qiang Xue
- * @version $Revision: $ $Date: $
- * @package System.Web.UI
- * @since 3.1
- */
-class TPageStateFormatter
-{
- /**
- * @param TPage
- * @param mixed state data
- * @return string serialized data
- */
- public static function serialize($page,$data)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateValidation())
- $str=$sm->hashData(Prado::serialize($data));
- else
- $str=Prado::serialize($data);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=gzcompress($str);
- if($page->getEnableStateEncryption())
- $str=$sm->encrypt($str);
- return base64_encode($str);
- }
-
- /**
- * @param TPage
- * @param string serialized data
- * @return mixed unserialized state data, null if data is corrupted
- */
- public static function unserialize($page,$data)
- {
- $str=base64_decode($data);
- if($str==='')
- return null;
- if($str!==false)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateEncryption())
- $str=$sm->decrypt($str);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=@gzuncompress($str);
- if($page->getEnableStateValidation())
- {
- if(($str=$sm->validateData($str))!==false)
- return Prado::unserialize($str);
- }
- else
- return Prado::unserialize($str);
- }
- return null;
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.UI.WebControls.*');
+Prado::using('System.Web.UI.TControl');
+Prado::using('System.Web.UI.WebControls.TWebControl');
+Prado::using('System.Web.UI.TCompositeControl');
+Prado::using('System.Web.UI.TTemplateControl');
+Prado::using('System.Web.UI.TForm');
+Prado::using('System.Web.UI.TClientScriptManager');
+
+/**
+ * TPage class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPage extends TTemplateControl
+{
+ /**
+ * system post fields
+ */
+ const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
+ const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
+ const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
+ const FIELD_PAGESTATE='PRADO_PAGESTATE';
+ const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
+ const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
+
+ /**
+ * @var array system post fields
+ */
+ private static $_systemPostFields=array(
+ 'PRADO_POSTBACK_TARGET'=>true,
+ 'PRADO_POSTBACK_PARAMETER'=>true,
+ 'PRADO_LASTFOCUS'=>true,
+ 'PRADO_PAGESTATE'=>true,
+ 'PRADO_CALLBACK_TARGET'=>true,
+ 'PRADO_CALLBACK_PARAMETER'=>true
+ );
+ /**
+ * @var TForm form instance
+ */
+ private $_form;
+ /**
+ * @var THead head instance
+ */
+ private $_head;
+ /**
+ * @var array list of registered validators
+ */
+ private $_validators=array();
+ /**
+ * @var boolean if validation has been performed
+ */
+ private $_validated=false;
+ /**
+ * @var TTheme page theme
+ */
+ private $_theme;
+ /**
+ * @var string page title set when Head is not in page yet
+ */
+ private $_title;
+ /**
+ * @var TTheme page stylesheet theme
+ */
+ private $_styleSheet;
+ /**
+ * @var TClientScriptManager client script manager
+ */
+ private $_clientScript;
+ /**
+ * @var TMap data post back by user
+ */
+ protected $_postData;
+ /**
+ * @var TMap postback data that is not handled during first invocation of LoadPostData.
+ */
+ protected $_restPostData;
+ /**
+ * @var array list of controls whose data have been changed due to the postback
+ */
+ protected $_controlsPostDataChanged=array();
+ /**
+ * @var array list of controls that need to load post data in the current request
+ */
+ protected $_controlsRequiringPostData=array();
+ /**
+ * @var array list of controls that need to load post data in the next postback
+ */
+ protected $_controlsRegisteredForPostData=array();
+ /**
+ * @var TControl control that needs to raise postback event
+ */
+ private $_postBackEventTarget;
+ /**
+ * @var string postback event parameter
+ */
+ private $_postBackEventParameter;
+ /**
+ * @var boolean whether the form has been rendered
+ */
+ protected $_formRendered=false;
+ /**
+ * @var boolean whether the current rendering is within a form
+ */
+ protected $_inFormRender=false;
+ /**
+ * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
+ */
+ private $_focus;
+ /**
+ * @var string page path to this page
+ */
+ private $_pagePath='';
+ /**
+ * @var boolean whether page state should be HMAC validated
+ */
+ private $_enableStateValidation=true;
+ /**
+ * @var boolean whether page state should be encrypted
+ */
+ private $_enableStateEncryption=false;
+ /**
+ * @var boolean whether page state should be compressed
+ * @since 3.1.6
+ */
+ private $_enableStateCompression=true;
+ /**
+ * @var string page state persister class name
+ */
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ /**
+ * @var mixed page state persister
+ */
+ private $_statePersister;
+ /**
+ * @var TStack stack used to store currently active caching controls
+ */
+ private $_cachingStack;
+ /**
+ * @var string state string to be stored on the client side
+ */
+ private $_clientState='';
+ /**
+ * @var array post data loader IDs.
+ */
+ protected $_postDataLoaders=array();
+ /**
+ * @var boolean true if loading post data.
+ */
+ protected $_isLoadingPostData=false;
+ /**
+ * @var boolean whether client supports javascript
+ */
+ private $_enableJavaScript=true;
+ /**
+ * @var THtmlWriter current html render writer
+ */
+ private $_writer;
+
+ /**
+ * Constructor.
+ * Sets the page object to itself.
+ * Derived classes must call parent implementation.
+ */
+ public function __construct()
+ {
+ $this->setPage($this);
+ }
+
+ /**
+ * Runs through the page lifecycles.
+ * @param THtmlTextWriter the HTML writer
+ */
+ public function run($writer)
+ {
+ Prado::trace("Running page life cycles",'System.Web.UI.TPage');
+ $this->_writer = $writer;
+
+ $this->determinePostBackMode();
+
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+
+ $this->_writer = null;
+ }
+
+ protected function processNormalRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected function processPostBackRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected static function decodeUTF8($data, $enc)
+ {
+ if(is_array($data))
+ {
+ foreach($data as $k=>$v)
+ $data[$k]=self::decodeUTF8($v, $enc);
+ return $data;
+ } elseif(is_string($data)) {
+ return iconv('UTF-8',$enc.'//IGNORE',$data);
+ } else {
+ return $data;
+ }
+ }
+
+ /**
+ * Sets Adapter to TActivePageAdapter and calls apter to process the
+ * callback request.
+ */
+ protected function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+
+ $this->setAdapter(new TActivePageAdapter($this));
+
+ // Decode Callback postData from UTF-8 to current Charset
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=self::decodeUTF8($v, $enc);
+
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+
+
+ $this->getAdapter()->processCallbackEvent($writer);
+
+/*
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+*/
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+/*
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+*/
+ $this->getAdapter()->renderCallbackResponse($writer);
+
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ /**
+ * Gets the callback client script handler that allows javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript interface to client-side javascript code.
+ */
+ public function getCallbackClient()
+ {
+ if($this->getAdapter() !== null)
+ return $this->getAdapter()->getCallbackClientHandler();
+ else
+ return new TCallbackClientScript();
+ }
+
+ /**
+ * Set a new callback client handler.
+ * @param TCallbackClientScript new callback client script handler.
+ */
+ public function setCallbackClient($client)
+ {
+ $this->getAdapter()->setCallbackClientHandler($client);
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ return $this->getAdapter()->getCallbackEventTarget();
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->getAdapter()->setCallbackEventTarget($control);
+ }
+
+ /**
+ * Callback parameter is decoded assuming JSON encoding.
+ * @return string callback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ return $this->getAdapter()->getCallbackEventParameter();
+ }
+
+ /**
+ * @param mixed callback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->getAdapter()->setCallbackEventParameter($value);
+ }
+
+ /**
+ * Register post data loaders for Callback to collect post data.
+ * This method should only be called by framework developers.
+ * @param TControl control that requires post data.
+ * @see TControl::preRenderRecursive();
+ */
+ public function registerPostDataLoader($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_postDataLoaders[$id] = true;
+ }
+
+ /**
+ * Get a list of IDs of controls that are enabled and require post data.
+ * @return array list of IDs implementing IPostBackDataHandler
+ */
+ public function getPostDataLoaders()
+ {
+ return array_keys($this->_postDataLoaders);
+ }
+
+ /**
+ * @return TForm the form on the page
+ */
+ public function getForm()
+ {
+ return $this->_form;
+ }
+
+ /**
+ * Registers a TForm instance to the page.
+ * Note, a page can contain at most one TForm instance.
+ * @param TForm the form on the page
+ * @throws TInvalidOperationException if this method is invoked twice or more.
+ */
+ public function setForm(TForm $form)
+ {
+ if($this->_form===null)
+ $this->_form=$form;
+ else
+ throw new TInvalidOperationException('page_form_duplicated');
+ }
+
+ /**
+ * Returns a list of registered validators.
+ * If validation group is specified, only the validators in that group will be returned.
+ * @param string validation group
+ * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
+ */
+ public function getValidators($validationGroup=null)
+ {
+ if(!$this->_validators)
+ $this->_validators=new TList;
+ if(empty($validationGroup) === true)
+ return $this->_validators;
+ else
+ {
+ $list=new TList;
+ foreach($this->_validators as $validator)
+ if($validator->getValidationGroup()===$validationGroup)
+ $list->add($validator);
+ return $list;
+ }
+ }
+
+ /**
+ * Performs input validation.
+ * This method will invoke the registered validators to perform the actual validation.
+ * If validation group is specified, only the validators in that group will be invoked.
+ * @param string validation group. If null, all validators will perform validation.
+ */
+ public function validate($validationGroup=null)
+ {
+ Prado::trace("Page validate()",'System.Web.UI.TPage');
+ $this->_validated=true;
+ if($this->_validators && $this->_validators->getCount())
+ {
+ if($validationGroup===null)
+ {
+ foreach($this->_validators as $validator)
+ $validator->validate();
+ }
+ else
+ {
+ foreach($this->_validators as $validator)
+ {
+ if($validator->getValidationGroup()===$validationGroup)
+ $validator->validate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether user input is valid or not.
+ * This method must be invoked after {@link validate} is called.
+ * @return boolean whether the user input is valid or not.
+ * @throws TInvalidOperationException if {@link validate} is not invoked yet.
+ */
+ public function getIsValid()
+ {
+ if($this->_validated)
+ {
+ if($this->_validators && $this->_validators->getCount())
+ {
+ foreach($this->_validators as $validator)
+ if(!$validator->getIsValid())
+ return false;
+ }
+ return true;
+ }
+ else
+ throw new TInvalidOperationException('page_isvalid_unknown');
+ }
+
+ /**
+ * @return TTheme the theme used for the page. Defaults to null.
+ */
+ public function getTheme()
+ {
+ if(is_string($this->_theme))
+ $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
+ return $this->_theme;
+ }
+
+ /**
+ * Sets the theme to be used for the page.
+ * @param string|TTheme the theme name or the theme object to be used for the page.
+ */
+ public function setTheme($value)
+ {
+ $this->_theme=empty($value)?null:$value;
+ }
+
+
+ /**
+ * @return TTheme the stylesheet theme used for the page. Defaults to null.
+ */
+ public function getStyleSheetTheme()
+ {
+ if(is_string($this->_styleSheet))
+ $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
+ return $this->_styleSheet;
+ }
+
+ /**
+ * Sets the stylesheet theme to be used for the page.
+ * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
+ */
+ public function setStyleSheetTheme($value)
+ {
+ $this->_styleSheet=empty($value)?null:$value;
+ }
+
+ /**
+ * Applies a skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied skin with
+ */
+ public function applyControlSkin($control)
+ {
+ if(($theme=$this->getTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * Applies a stylesheet skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied stylesheet skin with
+ */
+ public function applyControlStyleSheet($control)
+ {
+ if(($theme=$this->getStyleSheetTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * @return TClientScriptManager client script manager
+ */
+ public function getClientScript()
+ {
+ if(!$this->_clientScript) {
+ $className = $classPath = $this->getService()->getClientScriptManagerClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+
+ if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
+ throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
+
+ $this->_clientScript=new $className($this);
+ }
+ return $this->_clientScript;
+ }
+
+ /**
+ * Raises OnPreInit event.
+ * This method is invoked right before {@link onInit OnInit} stage.
+ * You may override this method to provide additional initialization that
+ * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
+ * {@link setStyleSheetTheme StyleSheetTheme}).
+ * Remember to call the parent implementation to ensure OnPreInit event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreInit($param)
+ {
+ $this->raiseEvent('OnPreInit',$this,$param);
+ }
+
+ /**
+ * Raises OnInitComplete event.
+ * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional initialization that
+ * should be done after {@link onInit OnInit}.
+ * Remember to call the parent implementation to ensure OnInitComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onInitComplete($param)
+ {
+ $this->raiseEvent('OnInitComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreLoad event.
+ * This method is invoked right before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done before {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnPreLoad event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreLoad($param)
+ {
+ $this->raiseEvent('OnPreLoad',$this,$param);
+ }
+
+ /**
+ * Raises OnLoadComplete event.
+ * This method is invoked right after {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done after {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onLoadComplete($param)
+ {
+ $this->raiseEvent('OnLoadComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreRenderComplete event.
+ * This method is invoked right after {@link onPreRender OnPreRender} stage.
+ * You may override this method to provide additional preparation for page rendering
+ * that should be done after {@link onPreRender OnPreRender}.
+ * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreRenderComplete($param)
+ {
+ $this->raiseEvent('OnPreRenderComplete',$this,$param);
+ $cs=$this->getClientScript();
+ $theme=$this->getTheme();
+ if($theme instanceof ITheme)
+ {
+ foreach($theme->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($theme->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ $styleSheet=$this->getStyleSheetTheme();
+ if($styleSheet instanceof ITheme)
+ {
+ foreach($styleSheet->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($styleSheet->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+
+ if($cs->getRequiresHead() && $this->getHead()===null)
+ throw new TConfigurationException('page_head_required');
+ }
+
+ /**
+ * Determines the media type of the CSS file.
+ * The media type is determined according to the following file name pattern:
+ * xxx.media-type.extension
+ * For example, 'mystyle.print.css' means its media type is 'print'.
+ * @param string CSS URL
+ * @return string media type of the CSS file
+ */
+ private function getCssMediaType($url)
+ {
+ $segs=explode('.',basename($url));
+ if(isset($segs[2]))
+ return $segs[count($segs)-2];
+ else
+ return '';
+ }
+
+ /**
+ * Raises OnSaveStateComplete event.
+ * This method is invoked right after {@link onSaveState OnSaveState} stage.
+ * You may override this method to provide additional logic after page state is saved.
+ * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onSaveStateComplete($param)
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,$param);
+ }
+
+ /**
+ * Determines whether the current page request is a postback.
+ * Call {@link getIsPostBack} to get the result.
+ */
+ private function determinePostBackMode()
+ {
+ $postData=$this->getRequest();
+ if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
+ $this->_postData=$postData;
+ }
+
+ /**
+ * @return boolean whether the current page request is a postback
+ */
+ public function getIsPostBack()
+ {
+ return $this->_postData!==null;
+ }
+
+ /**
+ * @return boolean whether this is a callback request
+ */
+ public function getIsCallback()
+ {
+ return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
+ }
+
+ /**
+ * Loads page state from persistent storage.
+ */
+ protected function loadPageState()
+ {
+ Prado::trace("Loading state",'System.Web.UI.TPage');
+ $state=$this->getStatePersister()->load();
+ $this->loadStateRecursive($state,$this->getEnableViewState());
+ }
+
+ /**
+ * Saves page state from persistent storage.
+ */
+ protected function savePageState()
+ {
+ Prado::trace("Saving state",'System.Web.UI.TPage');
+ $state=&$this->saveStateRecursive($this->getEnableViewState());
+ $this->getStatePersister()->save($state);
+ }
+
+ /**
+ * @param string the field name
+ * @return boolean whether the specified field is a system field in postback data
+ */
+ protected function isSystemPostField($field)
+ {
+ return isset(self::$_systemPostFields[$field]);
+ }
+
+ /**
+ * Registers a control for loading post data in the next postback.
+ * This method needs to be invoked if the control to load post data
+ * may not have a post variable in some cases. For example, a checkbox,
+ * if not checked, will not have a post value.
+ * @param TControl control registered for loading post data
+ */
+ public function registerRequiresPostData($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_controlsRegisteredForPostData[$id]=true;
+ $this->registerPostDataLoader($id);
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',array($id));
+ }
+
+ /**
+ * @return TControl the control responsible for the current postback event, null if nonexistent
+ */
+ public function getPostBackEventTarget()
+ {
+ if($this->_postBackEventTarget===null && $this->_postData!==null)
+ {
+ $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_postBackEventTarget=$this->findControl($eventTarget);
+ }
+ return $this->_postBackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise postback event in the current request.
+ * @param TControl control registered to raise postback event.
+ */
+ public function setPostBackEventTarget(TControl $control)
+ {
+ $this->_postBackEventTarget=$control;
+ }
+
+ /**
+ * @return string postback event parameter
+ */
+ public function getPostBackEventParameter()
+ {
+ if($this->_postBackEventParameter===null && $this->_postData!==null)
+ {
+ if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
+ $this->_postBackEventParameter='';
+ }
+ return $this->_postBackEventParameter;
+ }
+
+ /**
+ * @param string postback event parameter
+ */
+ public function setPostBackEventParameter($value)
+ {
+ $this->_postBackEventParameter=$value;
+ }
+
+ /**
+ * Processes post data.
+ * @param TMap post data to be processed
+ * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
+ */
+ protected function processPostData($postData,$beforeLoad)
+ {
+ $this->_isLoadingPostData=true;
+ if($beforeLoad)
+ $this->_restPostData=new TMap;
+ foreach($postData as $key=>$value)
+ {
+ if($this->isSystemPostField($key))
+ continue;
+ else if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else if($control instanceof IPostBackEventHandler &&
+ empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
+ {
+ $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
+ }
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ else if($beforeLoad)
+ $this->_restPostData->add($key,$value);
+ }
+
+ foreach($this->_controlsRequiringPostData as $key=>$value)
+ {
+ if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$this->_postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else
+ throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ }
+ $this->_isLoadingPostData=false;
+ }
+
+ /**
+ * @return boolean true if loading post data.
+ */
+ public function getIsLoadingPostData()
+ {
+ return $this->_isLoadingPostData;
+ }
+
+ /**
+ * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
+ */
+ protected function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+
+ /**
+ * Raises PostBack event.
+ */
+ protected function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+
+ /**
+ * @return boolean Whether form rendering is in progress
+ */
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+
+ /**
+ * Ensures the control is rendered within a form.
+ * @param TControl the control to be rendered
+ * @throws TConfigurationException if the control is outside of the form
+ */
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the beginning of its rendering
+ */
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the end of its rendering
+ */
+ public function endFormRender($writer)
+ {
+ if($this->_focus)
+ {
+ if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
+ $focus=$this->_focus->getClientID();
+ else
+ $focus=$this->_focus;
+ $this->getClientScript()->registerFocusControl($focus);
+ }
+ else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
+ $this->getClientScript()->registerFocusControl($lastFocus);
+ $this->_inFormRender=false;
+ }
+
+ /**
+ * Sets input focus on a control after the page is rendered to users.
+ * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
+ */
+ public function setFocus($value)
+ {
+ $this->_focus=$value;
+ }
+
+ /**
+ * @return boolean whether client supports javascript. Defaults to true.
+ */
+ public function getClientSupportsJavaScript()
+ {
+ return $this->_enableJavaScript;
+ }
+
+ /**
+ * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
+ */
+ public function setClientSupportsJavaScript($value)
+ {
+ $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THead page head, null if not available
+ */
+ public function getHead()
+ {
+ return $this->_head;
+ }
+
+ /**
+ * @param THead page head
+ * @throws TInvalidOperationException if a head already exists
+ */
+ public function setHead(THead $value)
+ {
+ if($this->_head)
+ throw new TInvalidOperationException('page_head_duplicated');
+ $this->_head=$value;
+ if($this->_title!==null)
+ {
+ $this->_head->setTitle($this->_title);
+ $this->_title=null;
+ }
+ }
+
+ /**
+ * @return string page title.
+ */
+ public function getTitle()
+ {
+ if($this->_head)
+ return $this->_head->getTitle();
+ else
+ return $this->_title===null ? '' : $this->_title;
+ }
+
+ /**
+ * Sets the page title.
+ * Note, a {@link THead} control needs to place on the page
+ * in order that this title be rendered.
+ * @param string page title. This will override the title set in {@link getHead Head}.
+ */
+ public function setTitle($value)
+ {
+ if($this->_head)
+ $this->_head->setTitle($value);
+ else
+ $this->_title=$value;
+ }
+
+ /**
+ * Returns the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @return string the state to be stored on the client side
+ */
+ public function getClientState()
+ {
+ return $this->_clientState;
+ }
+
+ /**
+ * Sets the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @param string the state to be stored on the client side
+ */
+ public function setClientState($state)
+ {
+ $this->_clientState=$state;
+ }
+
+ /**
+ * @return string the state postback from client side
+ */
+ public function getRequestClientState()
+ {
+ return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
+ }
+
+ /**
+ * @return string class name of the page state persister. Defaults to TPageStatePersister.
+ */
+ public function getStatePersisterClass()
+ {
+ return $this->_statePersisterClass;
+ }
+
+ /**
+ * @param string class name of the page state persister.
+ */
+ public function setStatePersisterClass($value)
+ {
+ $this->_statePersisterClass=$value;
+ }
+
+ /**
+ * @return IPageStatePersister page state persister
+ */
+ public function getStatePersister()
+ {
+ if($this->_statePersister===null)
+ {
+ $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
+ if(!($this->_statePersister instanceof IPageStatePersister))
+ throw new TInvalidDataTypeException('page_statepersister_invalid');
+ $this->_statePersister->setPage($this);
+ }
+ return $this->_statePersister;
+ }
+
+ /**
+ * @return boolean whether page state should be HMAC validated. Defaults to true.
+ */
+ public function getEnableStateValidation()
+ {
+ return $this->_enableStateValidation;
+ }
+
+ /**
+ * @param boolean whether page state should be HMAC validated.
+ */
+ public function setEnableStateValidation($value)
+ {
+ $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be encrypted. Defaults to false.
+ */
+ public function getEnableStateEncryption()
+ {
+ return $this->_enableStateEncryption;
+ }
+
+ /**
+ * @param boolean whether page state should be encrypted.
+ */
+ public function setEnableStateEncryption($value)
+ {
+ $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be compressed. Defaults to true.
+ * @since 3.1.6
+ */
+ public function getEnableStateCompression()
+ {
+ return $this->_enableStateCompression;
+ }
+
+ /**
+ * @param boolean whether page state should be compressed.
+ * @since 3.1.6
+ */
+ public function setEnableStateCompression($value)
+ {
+ $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the requested page path for this page
+ */
+ public function getPagePath()
+ {
+ return $this->_pagePath;
+ }
+
+ /**
+ * @param string the requested page path for this page
+ */
+ public function setPagePath($value)
+ {
+ $this->_pagePath=$value;
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript).
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerCachingAction($context,$funcName,$funcParams)
+ {
+ if($this->_cachingStack)
+ {
+ foreach($this->_cachingStack as $cache)
+ $cache->registerAction($context,$funcName,$funcParams);
+ }
+ }
+
+ /**
+ * @return TStack stack of {@link TOutputCache} objects
+ */
+ public function getCachingStack()
+ {
+ if(!$this->_cachingStack)
+ $this->_cachingStack=new TStack;
+ return $this->_cachingStack;
+ }
+
+ /**
+ * Flushes output
+ */
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
+}
+
+/**
+ * IPageStatePersister interface.
+ *
+ * IPageStatePersister interface is required for all page state persister
+ * classes.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1
+ */
+interface IPageStatePersister
+{
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage();
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page);
+ /**
+ * Saves state to persistent storage.
+ * @param mixed state to be stored
+ */
+ public function save($state);
+ /**
+ * Loads page state from persistent storage
+ * @return mixed the restored state
+ */
+ public function load();
+}
+
+
+/**
+ * TPageStateFormatter class.
+ *
+ * TPageStateFormatter is a utility class to transform the page state
+ * into and from a string that can be properly saved in persistent storage.
+ *
+ * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
+ * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
+ * TPageStateFormatter may do HMAC validation and encryption to prevent
+ * the state data from being tampered or viewed.
+ * The private keys and hashing/encryption methods are determined by
+ * {@link TApplication::getSecurityManager() SecurityManager}.
+ *
+ * @author Qiang Xue
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TPageStateFormatter
+{
+ /**
+ * @param TPage
+ * @param mixed state data
+ * @return string serialized data
+ */
+ public static function serialize($page,$data)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateValidation())
+ $str=$sm->hashData(Prado::serialize($data));
+ else
+ $str=Prado::serialize($data);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=gzcompress($str);
+ if($page->getEnableStateEncryption())
+ $str=$sm->encrypt($str);
+ return base64_encode($str);
+ }
+
+ /**
+ * @param TPage
+ * @param string serialized data
+ * @return mixed unserialized state data, null if data is corrupted
+ */
+ public static function unserialize($page,$data)
+ {
+ $str=base64_decode($data);
+ if($str==='')
+ return null;
+ if($str!==false)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateEncryption())
+ $str=$sm->decrypt($str);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return Prado::unserialize($str);
+ }
+ else
+ return Prado::unserialize($str);
+ }
+ return null;
+ }
+}
diff --git a/framework/Web/UI/TPageStatePersister.php b/framework/Web/UI/TPageStatePersister.php
index 18590a77..183cde13 100644
--- a/framework/Web/UI/TPageStatePersister.php
+++ b/framework/Web/UI/TPageStatePersister.php
@@ -1,71 +1,71 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TPageStatePersister class
- *
- * TPageStatePersister implements a page state persistent method based on
- * form hidden fields.
- *
- * Since page state can be very big for complex pages, consider using
- * alternative persisters, such as {@link TSessionPageStatePersister},
- * which store page state on the server side and thus reduce the network
- * traffic for transmitting bulky page state.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TPageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_page;
-
- /**
- * @return TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * Saves state in hidden fields.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
- }
-
- /**
- * Loads page state from hidden fields.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- return $data;
- else
- throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TPageStatePersister class
+ *
+ * TPageStatePersister implements a page state persistent method based on
+ * form hidden fields.
+ *
+ * Since page state can be very big for complex pages, consider using
+ * alternative persisters, such as {@link TSessionPageStatePersister},
+ * which store page state on the server side and thus reduce the network
+ * traffic for transmitting bulky page state.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_page;
+
+ /**
+ * @return TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Saves state in hidden fields.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
+ }
+
+ /**
+ * Loads page state from hidden fields.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ return $data;
+ else
+ throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TSessionPageStatePersister.php b/framework/Web/UI/TSessionPageStatePersister.php
index 4c2537df..a6d26f7a 100644
--- a/framework/Web/UI/TSessionPageStatePersister.php
+++ b/framework/Web/UI/TSessionPageStatePersister.php
@@ -1,131 +1,131 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TSessionPageStatePersister class
- *
- * TSessionPageStatePersister implements a page state persistent method based on
- * sessions. Page state are stored in user sessions and therefore, this persister
- * requires session to be started and available.
- *
- * TSessionPageStatePersister keeps limited number of history states in session,
- * mainly to preserve the precious server storage. The number is specified
- * by {@link setHistorySize HistorySize}, which defaults to 10.
- *
- * There are a couple of ways to use TSessionPageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TSessionPageStatePersister instance there.
- * Or one can configure the pages to use TSessionPageStatePersister in page configurations
- * as follows,
- *
- *
- *
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TSessionPageStatePersister, use
- *
- *
- *
- *
- *
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1
- */
-class TSessionPageStatePersister extends TComponent implements IPageStatePersister
-{
- const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
- const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
-
- private $_page;
- private $_historySize=10;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return integer maximum number of page states that should be kept in session. Defaults to 10.
- */
- public function getHistorySize()
- {
- return $this->_historySize;
- }
-
- /**
- * @param integer maximum number of page states that should be kept in session
- * @throws TInvalidDataValueException if the number is smaller than 1.
- */
- public function setHistorySize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>0)
- $this->_historySize=$value;
- else
- throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
- }
- /**
- * Saves state in session.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $session=$this->_page->getSession();
- $session->open();
- $data=serialize($state);
- $timestamp=(string)microtime(true);
- $key=self::STATE_SESSION_KEY.$timestamp;
- $session->add($key,$data);
- if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
- $queue=array();
- $queue[]=$key;
- if(count($queue)>$this->getHistorySize())
- {
- $expiredKey=array_shift($queue);
- $session->remove($expiredKey);
- }
- $session->add(self::QUEUE_SESSION_KEY,$queue);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from session.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $session=$this->_page->getSession();
- $session->open();
- $key=self::STATE_SESSION_KEY.$timestamp;
- if(($data=$session->itemAt($key))!==null)
- return unserialize($data);
- }
- throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TSessionPageStatePersister class
+ *
+ * TSessionPageStatePersister implements a page state persistent method based on
+ * sessions. Page state are stored in user sessions and therefore, this persister
+ * requires session to be started and available.
+ *
+ * TSessionPageStatePersister keeps limited number of history states in session,
+ * mainly to preserve the precious server storage. The number is specified
+ * by {@link setHistorySize HistorySize}, which defaults to 10.
+ *
+ * There are a couple of ways to use TSessionPageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TSessionPageStatePersister instance there.
+ * Or one can configure the pages to use TSessionPageStatePersister in page configurations
+ * as follows,
+ *
+ *
+ *
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TSessionPageStatePersister, use
+ *
+ *
+ *
+ *
+ *
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TSessionPageStatePersister extends TComponent implements IPageStatePersister
+{
+ const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
+ const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
+
+ private $_page;
+ private $_historySize=10;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return integer maximum number of page states that should be kept in session. Defaults to 10.
+ */
+ public function getHistorySize()
+ {
+ return $this->_historySize;
+ }
+
+ /**
+ * @param integer maximum number of page states that should be kept in session
+ * @throws TInvalidDataValueException if the number is smaller than 1.
+ */
+ public function setHistorySize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>0)
+ $this->_historySize=$value;
+ else
+ throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
+ }
+ /**
+ * Saves state in session.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $data=serialize($state);
+ $timestamp=(string)microtime(true);
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ $session->add($key,$data);
+ if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
+ $queue=array();
+ $queue[]=$key;
+ if(count($queue)>$this->getHistorySize())
+ {
+ $expiredKey=array_shift($queue);
+ $session->remove($expiredKey);
+ }
+ $session->add(self::QUEUE_SESSION_KEY,$queue);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from session.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ if(($data=$session->itemAt($key))!==null)
+ return unserialize($data);
+ }
+ throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TTemplateControl.php b/framework/Web/UI/TTemplateControl.php
index 400c1059..9b26728d 100644
--- a/framework/Web/UI/TTemplateControl.php
+++ b/framework/Web/UI/TTemplateControl.php
@@ -1,243 +1,243 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TCompositeControl class
- */
-Prado::using('System.Web.UI.TCompositeControl');
-
-/**
- * TTemplateControl class.
- * TTemplateControl is the base class for all controls that use templates.
- * By default, a control template is assumed to be in a file under the same
- * directory with the control class file. They have the same file name and
- * different extension name. For template file, the extension name is ".tpl".
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateControl extends TCompositeControl
-{
- /**
- * template file extension.
- */
- const EXT_TEMPLATE='.tpl';
-
- /**
- * @var ITemplate the parsed template structure shared by the same control class
- */
- private static $_template=array();
- /**
- * @var ITemplate the parsed template structure specific for this control instance
- */
- private $_localTemplate=null;
- /**
- * @var TTemplateControl the master control if any
- */
- private $_master=null;
- /**
- * @var string master control class name
- */
- private $_masterClass='';
- /**
- * @var array list of TContent controls
- */
- private $_contents=array();
- /**
- * @var array list of TContentPlaceHolder controls
- */
- private $_placeholders=array();
-
- /**
- * Returns the template object associated with this control object.
- * @return ITemplate|null the parsed template, null if none
- */
- public function getTemplate()
- {
- if($this->_localTemplate===null)
- {
- $class=get_class($this);
- if(!isset(self::$_template[$class]))
- self::$_template[$class]=$this->loadTemplate();
- return self::$_template[$class];
- }
- else
- return $this->_localTemplate;
- }
-
- /**
- * Sets the parsed template.
- * Note, the template will be applied to the whole control class.
- * This method should only be used by framework and control developers.
- * @param ITemplate the parsed template
- */
- public function setTemplate($value)
- {
- $this->_localTemplate=$value;
- }
-
- /**
- * @return boolean whether this control is a source template control.
- * A source template control loads its template from external storage,
- * such as file, db, rather than from within another template.
- */
- public function getIsSourceTemplateControl()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getIsSourceTemplate();
- else
- return false;
- }
-
- /**
- * @return string the directory containing the template. Empty if no template available.
- */
- public function getTemplateDirectory()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getContextPath();
- else
- return '';
- }
-
- /**
- * Loads the template associated with this control class.
- * @return ITemplate the parsed template structure
- */
- protected function loadTemplate()
- {
- Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
- $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
- return $template;
- }
-
- /**
- * Creates child controls.
- * This method is overridden to load and instantiate control template.
- * This method should only be used by framework and control developers.
- */
- public function createChildControls()
- {
- if($tpl=$this->getTemplate())
- {
- foreach($tpl->getDirective() as $name=>$value)
- {
- if(is_string($value))
- $this->setSubProperty($name,$value);
- else
- throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
- }
- $tpl->instantiateIn($this);
- }
- }
-
- /**
- * Registers a content control.
- * @param string ID of the content
- * @param TContent
- */
- public function registerContent($id,TContent $object)
- {
- if(isset($this->_contents[$id]))
- throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
- else
- $this->_contents[$id]=$object;
- }
-
- /**
- * Registers a content placeholder to this template control.
- * This method should only be used by framework and control developers.
- * @param string placeholder ID
- * @param TContentPlaceHolder placeholder control
- */
- public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
- {
- if(isset($this->_placeholders[$id]))
- throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
- else
- $this->_placeholders[$id]=$object;
- }
-
- /**
- * @return string master class name (in namespace form)
- */
- public function getMasterClass()
- {
- return $this->_masterClass;
- }
-
- /**
- * @param string master control class name (in namespace form)
- */
- public function setMasterClass($value)
- {
- $this->_masterClass=$value;
- }
-
- /**
- * @return TTemplateControl|null master control associated with this control, null if none
- */
- public function getMaster()
- {
- return $this->_master;
- }
-
- /**
- * Injects all content controls (and their children) to the corresponding content placeholders.
- * This method should only be used by framework and control developers.
- * @param string ID of the content control
- * @param TContent the content to be injected
- */
- public function injectContent($id,$content)
- {
- if(isset($this->_placeholders[$id]))
- {
- $placeholder=$this->_placeholders[$id];
- $controls=$placeholder->getParent()->getControls();
- $loc=$controls->remove($placeholder);
- $controls->insertAt($loc,$content);
- }
- else
- throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
- }
-
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first,
- * and if master class is set, master will be applied.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->_masterClass!=='')
- {
- $master=Prado::createComponent($this->_masterClass);
- if(!($master instanceof TTemplateControl))
- throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
- $this->_master=$master;
- $this->getControls()->clear();
- $this->getControls()->add($master);
- $master->ensureChildControls();
- foreach($this->_contents as $id=>$content)
- $master->injectContent($id,$content);
- }
- else if(!empty($this->_contents))
- throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TCompositeControl class
+ */
+Prado::using('System.Web.UI.TCompositeControl');
+
+/**
+ * TTemplateControl class.
+ * TTemplateControl is the base class for all controls that use templates.
+ * By default, a control template is assumed to be in a file under the same
+ * directory with the control class file. They have the same file name and
+ * different extension name. For template file, the extension name is ".tpl".
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateControl extends TCompositeControl
+{
+ /**
+ * template file extension.
+ */
+ const EXT_TEMPLATE='.tpl';
+
+ /**
+ * @var ITemplate the parsed template structure shared by the same control class
+ */
+ private static $_template=array();
+ /**
+ * @var ITemplate the parsed template structure specific for this control instance
+ */
+ private $_localTemplate=null;
+ /**
+ * @var TTemplateControl the master control if any
+ */
+ private $_master=null;
+ /**
+ * @var string master control class name
+ */
+ private $_masterClass='';
+ /**
+ * @var array list of TContent controls
+ */
+ private $_contents=array();
+ /**
+ * @var array list of TContentPlaceHolder controls
+ */
+ private $_placeholders=array();
+
+ /**
+ * Returns the template object associated with this control object.
+ * @return ITemplate|null the parsed template, null if none
+ */
+ public function getTemplate()
+ {
+ if($this->_localTemplate===null)
+ {
+ $class=get_class($this);
+ if(!isset(self::$_template[$class]))
+ self::$_template[$class]=$this->loadTemplate();
+ return self::$_template[$class];
+ }
+ else
+ return $this->_localTemplate;
+ }
+
+ /**
+ * Sets the parsed template.
+ * Note, the template will be applied to the whole control class.
+ * This method should only be used by framework and control developers.
+ * @param ITemplate the parsed template
+ */
+ public function setTemplate($value)
+ {
+ $this->_localTemplate=$value;
+ }
+
+ /**
+ * @return boolean whether this control is a source template control.
+ * A source template control loads its template from external storage,
+ * such as file, db, rather than from within another template.
+ */
+ public function getIsSourceTemplateControl()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getIsSourceTemplate();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the directory containing the template. Empty if no template available.
+ */
+ public function getTemplateDirectory()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getContextPath();
+ else
+ return '';
+ }
+
+ /**
+ * Loads the template associated with this control class.
+ * @return ITemplate the parsed template structure
+ */
+ protected function loadTemplate()
+ {
+ Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
+ $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
+ return $template;
+ }
+
+ /**
+ * Creates child controls.
+ * This method is overridden to load and instantiate control template.
+ * This method should only be used by framework and control developers.
+ */
+ public function createChildControls()
+ {
+ if($tpl=$this->getTemplate())
+ {
+ foreach($tpl->getDirective() as $name=>$value)
+ {
+ if(is_string($value))
+ $this->setSubProperty($name,$value);
+ else
+ throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
+ }
+ $tpl->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Registers a content control.
+ * @param string ID of the content
+ * @param TContent
+ */
+ public function registerContent($id,TContent $object)
+ {
+ if(isset($this->_contents[$id]))
+ throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
+ else
+ $this->_contents[$id]=$object;
+ }
+
+ /**
+ * Registers a content placeholder to this template control.
+ * This method should only be used by framework and control developers.
+ * @param string placeholder ID
+ * @param TContentPlaceHolder placeholder control
+ */
+ public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
+ {
+ if(isset($this->_placeholders[$id]))
+ throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
+ else
+ $this->_placeholders[$id]=$object;
+ }
+
+ /**
+ * @return string master class name (in namespace form)
+ */
+ public function getMasterClass()
+ {
+ return $this->_masterClass;
+ }
+
+ /**
+ * @param string master control class name (in namespace form)
+ */
+ public function setMasterClass($value)
+ {
+ $this->_masterClass=$value;
+ }
+
+ /**
+ * @return TTemplateControl|null master control associated with this control, null if none
+ */
+ public function getMaster()
+ {
+ return $this->_master;
+ }
+
+ /**
+ * Injects all content controls (and their children) to the corresponding content placeholders.
+ * This method should only be used by framework and control developers.
+ * @param string ID of the content control
+ * @param TContent the content to be injected
+ */
+ public function injectContent($id,$content)
+ {
+ if(isset($this->_placeholders[$id]))
+ {
+ $placeholder=$this->_placeholders[$id];
+ $controls=$placeholder->getParent()->getControls();
+ $loc=$controls->remove($placeholder);
+ $controls->insertAt($loc,$content);
+ }
+ else
+ throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
+ }
+
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first,
+ * and if master class is set, master will be applied.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->_masterClass!=='')
+ {
+ $master=Prado::createComponent($this->_masterClass);
+ if(!($master instanceof TTemplateControl))
+ throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
+ $this->_master=$master;
+ $this->getControls()->clear();
+ $this->getControls()->add($master);
+ $master->ensureChildControls();
+ foreach($this->_contents as $id=>$content)
+ $master->injectContent($id,$content);
+ }
+ else if(!empty($this->_contents))
+ throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
+ parent::initRecursive($namingContainer);
+ }
+}
+
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 4d17806b..f884cd65 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -1,1075 +1,1075 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TOutputCache class file
- */
-Prado::using('System.Web.UI.WebControls.TOutputCache');
-
-/**
- * TTemplateManager class
- *
- * TTemplateManager manages the loading and parsing of control templates.
- *
- * There are two ways of loading a template, either by the associated template
- * control class name, or the template file name.
- * The former is via calling {@link getTemplateByClassName}, which tries to
- * locate the corresponding template file under the directory containing
- * the class file. The name of the template file is the class name with
- * the extension '.tpl'. To load a template from a template file path,
- * call {@link getTemplateByFileName}.
- *
- * By default, TTemplateManager is registered with {@link TPageService} as the
- * template manager module that can be accessed via {@link TPageService::getTemplateManager()}.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateManager extends TModule
-{
- /**
- * Template file extension
- */
- const TEMPLATE_FILE_EXT='.tpl';
- /**
- * Prefix of the cache variable name for storing parsed templates
- */
- const TEMPLATE_CACHE_PREFIX='prado:template:';
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * It starts output buffer if it is enabled.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- $this->getService()->setTemplateManager($this);
- }
-
- /**
- * Loads the template corresponding to the specified class name.
- * @return ITemplate template for the class name, null if template doesn't exist.
- */
- public function getTemplateByClassName($className)
- {
- $class=new ReflectionClass($className);
- $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
- return $this->getTemplateByFileName($tplFile);
- }
-
- /**
- * Loads the template from the specified file.
- * @return ITemplate template parsed from the specified file, null if the file doesn't exist.
- */
- public function getTemplateByFileName($fileName)
- {
- if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
- {
- Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager');
- if(($cache=$this->getApplication()->getCache())===null)
- return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- else
- {
- $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
- if(is_array($array))
- {
- list($template,$timestamps)=$array;
- if($this->getApplication()->getMode()===TApplicationMode::Performance)
- return $template;
- $cacheValid=true;
- foreach($timestamps as $tplFile=>$timestamp)
- {
- if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
- {
- $cacheValid=false;
- break;
- }
- }
- if($cacheValid)
- return $template;
- }
- $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- $includedFiles=$template->getIncludedFiles();
- $timestamps=array();
- $timestamps[$fileName]=filemtime($fileName);
- foreach($includedFiles as $includedFile)
- $timestamps[$includedFile]=filemtime($includedFile);
- $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
- return $template;
- }
- }
- else
- return null;
- }
-
- /**
- * Finds a localized template file.
- * @param string template file.
- * @return string|null a localized template file if found, null otherwise.
- */
- protected function getLocalizedTemplate($filename)
- {
- if(($app=$this->getApplication()->getGlobalization(false))===null)
- return is_file($filename)?$filename:null;
- foreach($app->getLocalizedResource($filename) as $file)
- {
- if(($file=realpath($file))!==false && is_file($file))
- return $file;
- }
- return null;
- }
-}
-
-/**
- * TTemplate implements PRADO template parsing logic.
- * A TTemplate object represents a parsed PRADO control template.
- * It can instantiate the template as child controls of a specified control.
- * The template format is like HTML, with the following special tags introduced,
- * - component tags: a component tag represents the configuration of a component.
- * The tag name is in the format of com:ComponentType, where ComponentType is the component
- * class name. Component tags must be well-formed. Attributes of the component tag
- * are treated as either property initial values, event handler attachment, or regular
- * tag attributes.
- * - property tags: property tags are used to set large block of attribute values.
- * The property tag name is in the format of where AttributeName
- * can be a property name, an event name or a regular tag attribute name.
- * - group subproperty tags: subproperties of a common property can be configured using
- *
- * - directive: directive specifies the property values for the template owner.
- * It is in the format of <%@ property name-value pairs %>;
- * - expressions: They are in the format of <%= PHP expression %> and <%% PHP statements %>
- * - comments: There are two kinds of comments, regular HTML comments and special template comments.
- * The former is in the format of , which will be treated as text strings.
- * The latter is in the format of , which will be stripped out.
- *
- * Tags other than the above are not required to be well-formed.
- *
- * A TTemplate object represents a parsed PRADO template. To instantiate the template
- * for a particular control, call {@link instantiateIn($control)}, which
- * will create and intialize all components specified in the template and
- * set their parent as $control.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplate extends TApplicationComponent implements ITemplate
-{
- /**
- * '' - template comments
- * '' - HTML comments
- * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags
- * '<\/?prop:([\w\.]+)\s*>' - property tags
- * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives
- * '<%[%#~\/\\$=\\[](.*?)%>' - expressions
- * ')*)\s*\/>' - group subproperty tags
- */
- const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS';
-
- /**
- * Different configurations of component property/event/attribute
- */
- const CONFIG_DATABIND=0;
- const CONFIG_EXPRESSION=1;
- const CONFIG_ASSET=2;
- const CONFIG_PARAMETER=3;
- const CONFIG_LOCALIZATION=4;
- const CONFIG_TEMPLATE=5;
-
- /**
- * @var array list of component tags and strings
- */
- private $_tpl=array();
- /**
- * @var array list of directive settings
- */
- private $_directive=array();
- /**
- * @var string context path
- */
- private $_contextPath;
- /**
- * @var string template file path (if available)
- */
- private $_tplFile=null;
- /**
- * @var integer the line number that parsing starts from (internal use)
- */
- private $_startingLine=0;
- /**
- * @var string template content to be parsed
- */
- private $_content;
- /**
- * @var boolean whether this template is a source template
- */
- private $_sourceTemplate=true;
- /**
- * @var string hash code of the template
- */
- private $_hashCode='';
- private $_tplControl=null;
- private $_includedFiles=array();
- private $_includeAtLine=array();
- private $_includeLines=array();
-
-
- /**
- * Constructor.
- * The template will be parsed after construction.
- * @param string the template string
- * @param string the template context directory
- * @param string the template file, null if no file
- * @param integer the line number that parsing starts from (internal use)
- * @param boolean whether this template is a source template, i.e., this template is loaded from
- * some external storage rather than from within another template.
- */
- public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
- {
- $this->_sourceTemplate=$sourceTemplate;
- $this->_contextPath=$contextPath;
- $this->_tplFile=$tplFile;
- $this->_startingLine=$startingLine;
- $this->_content=$template;
- $this->_hashCode=md5($template);
- $this->parse($template);
- $this->_content=null; // reset to save memory
- }
-
- /**
- * @return string template file path if available, null otherwise.
- */
- public function getTemplateFile()
- {
- return $this->_tplFile;
- }
-
- /**
- * @return boolean whether this template is a source template, i.e., this template is loaded from
- * some external storage rather than from within another template.
- */
- public function getIsSourceTemplate()
- {
- return $this->_sourceTemplate;
- }
-
- /**
- * @return string context directory path
- */
- public function getContextPath()
- {
- return $this->_contextPath;
- }
-
- /**
- * @return array name-value pairs declared in the directive
- */
- public function getDirective()
- {
- return $this->_directive;
- }
-
- /**
- * @return string hash code that can be used to identify the template
- */
- public function getHashCode()
- {
- return $this->_hashCode;
- }
-
- /**
- * @return array the parsed template
- */
- public function &getItems()
- {
- return $this->_tpl;
- }
-
- /**
- * Instantiates the template.
- * Content in the template will be instantiated as components and text strings
- * and passed to the specified parent control.
- * @param TControl the control who owns the template
- * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control.
- */
- public function instantiateIn($tplControl,$parentControl=null)
- {
- $this->_tplControl=$tplControl;
- if($parentControl===null)
- $parentControl=$tplControl;
- if(($page=$tplControl->getPage())===null)
- $page=$this->getService()->getRequestedPage();
- $controls=array();
- $directChildren=array();
- foreach($this->_tpl as $key=>$object)
- {
- if($object[0]===-1)
- $parent=$parentControl;
- else if(isset($controls[$object[0]]))
- $parent=$controls[$object[0]];
- else
- continue;
- if(isset($object[2])) // component
- {
- $component=Prado::createComponent($object[1]);
- $properties=&$object[2];
- if($component instanceof TControl)
- {
- if($component instanceof TOutputCache)
- $component->setCacheKeyPrefix($this->_hashCode.$key);
- $component->setTemplateControl($tplControl);
- if(isset($properties['id']))
- {
- if(is_array($properties['id']))
- $properties['id']=$component->evaluateExpression($properties['id'][1]);
- $tplControl->registerObject($properties['id'],$component);
- }
- if(isset($properties['skinid']))
- {
- if(is_array($properties['skinid']))
- $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
- else
- $component->setSkinID($properties['skinid']);
- unset($properties['skinid']);
- }
-
- $component->trackViewState(false);
-
- $component->applyStyleSheetSkin($page);
- foreach($properties as $name=>$value)
- $this->configureControl($component,$name,$value);
-
- $component->trackViewState(true);
-
- if($parent===$parentControl)
- $directChildren[]=$component;
- else
- $component->createdOnTemplate($parent);
- if($component->getAllowChildControls())
- $controls[$key]=$component;
- }
- else if($component instanceof TComponent)
- {
- $controls[$key]=$component;
- if(isset($properties['id']))
- {
- if(is_array($properties['id']))
- $properties['id']=$component->evaluateExpression($properties['id'][1]);
- $tplControl->registerObject($properties['id'],$component);
- if(!$component->hasProperty('id'))
- unset($properties['id']);
- }
- foreach($properties as $name=>$value)
- $this->configureComponent($component,$name,$value);
- if($parent===$parentControl)
- $directChildren[]=$component;
- else
- $component->createdOnTemplate($parent);
- }
- }
- else
- {
- if($object[1] instanceof TCompositeLiteral)
- {
- // need to clone a new object because the one in template is reused
- $o=clone $object[1];
- $o->setContainer($tplControl);
- if($parent===$parentControl)
- $directChildren[]=$o;
- else
- $parent->addParsedObject($o);
- }
- else
- {
- if($parent===$parentControl)
- $directChildren[]=$object[1];
- else
- $parent->addParsedObject($object[1]);
- }
- }
- }
- // delay setting parent till now because the parent may cause
- // the child to do lifecycle catchup which may cause problem
- // if the child needs its own child controls.
- foreach($directChildren as $control)
- {
- if($control instanceof TComponent)
- $control->createdOnTemplate($parentControl);
- else
- $parentControl->addParsedObject($control);
- }
- }
-
- /**
- * Configures a property/event of a control.
- * @param TControl control to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureControl($control,$name,$value)
- {
- if(strncasecmp($name,'on',2)===0) // is an event
- $this->configureEvent($control,$name,$value,$control);
- else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
- $this->configureProperty($control,$name,$value);
- else // is a subproperty
- $this->configureSubProperty($control,$name,$value);
- }
-
- /**
- * Configures a property of a non-control component.
- * @param TComponent component to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureComponent($component,$name,$value)
- {
- if(strpos($name,'.')===false) // is a simple property or custom attribute
- $this->configureProperty($component,$name,$value);
- else // is a subproperty
- $this->configureSubProperty($component,$name,$value);
- }
-
- /**
- * Configures an event for a control.
- * @param TControl control to be configured
- * @param string event name
- * @param string event handler
- * @param TControl context control
- */
- protected function configureEvent($control,$name,$value,$contextControl)
- {
- if(strpos($value,'.')===false)
- $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
- else
- $control->attachEventHandler($name,array($contextControl,$value));
- }
-
- /**
- * Configures a simple property for a component.
- * @param TComponent component to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureProperty($component,$name,$value)
- {
- if(is_array($value))
- {
- switch($value[0])
- {
- case self::CONFIG_DATABIND:
- $component->bindProperty($name,$value[1]);
- break;
- case self::CONFIG_EXPRESSION:
- if($component instanceof TControl)
- $component->autoBindProperty($name,$value[1]);
- else
- {
- $setter='set'.$name;
- $component->$setter($this->_tplControl->evaluateExpression($value[1]));
- }
- break;
- case self::CONFIG_TEMPLATE:
- $setter='set'.$name;
- $component->$setter($value[1]);
- break;
- case self::CONFIG_ASSET: // asset URL
- $setter='set'.$name;
- $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
- $component->$setter($url);
- break;
- case self::CONFIG_PARAMETER: // application parameter
- $setter='set'.$name;
- $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case self::CONFIG_LOCALIZATION:
- $setter='set'.$name;
- $component->$setter(Prado::localize($value[1]));
- break;
- default: // an error if reaching here
- throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
- break;
- }
- }
- else
- {
- if (substr($name,0,2)=='js')
- if ($value and !($value instanceof TJavaScriptLiteral))
- $value = new TJavaScriptLiteral($value);
- $setter='set'.$name;
- $component->$setter($value);
- }
- }
-
- /**
- * Configures a subproperty for a component.
- * @param TComponent component to be configured
- * @param string subproperty name
- * @param mixed subproperty initial value
- */
- protected function configureSubProperty($component,$name,$value)
- {
- if(is_array($value))
- {
- switch($value[0])
- {
- case self::CONFIG_DATABIND: // databinding
- $component->bindProperty($name,$value[1]);
- break;
- case self::CONFIG_EXPRESSION: // expression
- if($component instanceof TControl)
- $component->autoBindProperty($name,$value[1]);
- else
- $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
- break;
- case self::CONFIG_TEMPLATE:
- $component->setSubProperty($name,$value[1]);
- break;
- case self::CONFIG_ASSET: // asset URL
- $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
- $component->setSubProperty($name,$url);
- break;
- case self::CONFIG_PARAMETER: // application parameter
- $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case self::CONFIG_LOCALIZATION:
- $component->setSubProperty($name,Prado::localize($value[1]));
- break;
- default: // an error if reaching here
- throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
- break;
- }
- }
- else
- $component->setSubProperty($name,$value);
- }
-
- /**
- * Parses a template string.
- *
- * This template parser recognizes five types of data:
- * regular string, well-formed component tags, well-formed property tags, directives, and expressions.
- *
- * The parsing result is returned as an array. Each array element can be of three types:
- * - a string, 0: container index; 1: string content;
- * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs)
- * If a directive is found in the template, it will be parsed and can be
- * retrieved via {@link getDirective}, which returns an array consisting of
- * name-value pairs in the directive.
- *
- * Note, attribute names are treated as case-insensitive and will be turned into lower cases.
- * Component and directive types are case-sensitive.
- * Container index is the index to the array element that stores the container object.
- * If an object has no container, its container index is -1.
- *
- * @param string the template string
- * @throws TConfigurationException if a parsing error is encountered
- */
- protected function parse($input)
- {
- $input=$this->preprocess($input);
- $tpl=&$this->_tpl;
- $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
- $expectPropEnd=false;
- $textStart=0;
- $stack=array();
- $container=-1;
- $matchEnd=0;
- $c=0;
- $this->_directive=null;
- try
- {
- for($i=0;$i<$n;++$i)
- {
- $match=&$matches[$i];
- $str=$match[0][0];
- $matchStart=$match[0][1];
- $matchEnd=$matchStart+strlen($str)-1;
- if(strpos($str,'$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $type=$match[1][0];
- $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
- $this->validateAttributes($type,$attributes);
- $tpl[$c++]=array($container,$type,$attributes);
- if($str[strlen($str)-2]!=='/') // open tag
- {
- $stack[] = $type;
- $container=$c-1;
- }
- }
- else if(strpos($str,' $textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $type=$match[1][0];
-
- if(empty($stack))
- throw new TConfigurationException('template_closingtag_unexpected',"");
-
- $name=array_pop($stack);
- if($name!==$type)
- {
- $tag=$name[0]==='@' ? ' ' : "";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- $container=$tpl[$container][0];
- }
- else if(strpos($str,'<%@')===0) // directive
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- if(isset($tpl[0]) || $this->_directive!==null)
- throw new TConfigurationException('template_directive_nonunique');
- $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
- }
- else if(strpos($str,'<%')===0) // expression
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $literal=trim($match[5][0]);
- if($str[2]==='=') // expression
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
- else if($str[2]==='%') // statements
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
- else if($str[2]==='#')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
- else if($str[2]==='$')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
- else if($str[2]==='~')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
- else if($str[2]==='/')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
- else if($str[2]==='[')
- {
- $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
- }
- }
- else if(strpos($str,' ')===strlen($str)-2) //subproperties
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $prop=strtolower($match[6][0]);
- $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
- $attributes=array();
- foreach($attrs as $name=>$value)
- $attributes[$prop.'.'.$name]=$value;
- $type=$tpl[$container][1];
- $this->validateAttributes($type,$attributes);
- foreach($attributes as $name=>$value)
- {
- if(isset($tpl[$container][2][$name]))
- throw new TConfigurationException('template_property_duplicated',$name);
- $tpl[$container][2][$name]=$value;
- }
- }
- else // regular property
- {
- $prop=strtolower($match[3][0]);
- $stack[] = '@'.$prop;
- if(!$expectPropEnd)
- {
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $expectPropEnd=true;
- }
- }
- }
- else if(strpos($str,' ");
- $name=array_pop($stack);
- if($name!=='@'.$prop)
- {
- $tag=$name[0]==='@' ? '' : "";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
- {
- if($matchStart>$textStart)
- {
- $value=substr($input,$textStart,$matchStart-$textStart);
- if(substr($prop,-8,8)==='template')
- $value=$this->parseTemplateProperty($value,$textStart);
- else
- $value=$this->parseAttribute($value);
- if($container>=0)
- {
- $type=$tpl[$container][1];
- $this->validateAttributes($type,array($prop=>$value));
- if(isset($tpl[$container][2][$prop]))
- throw new TConfigurationException('template_property_duplicated',$prop);
- $tpl[$container][2][$prop]=$value;
- }
- else // a property for the template control
- $this->_directive[$prop]=$value;
- $textStart=$matchEnd+1;
- }
- $expectPropEnd=false;
- }
- }
- else if(strpos($str,', which will be treated as text strings.
+ * The latter is in the format of , which will be stripped out.
+ *
+ * Tags other than the above are not required to be well-formed.
+ *
+ * A TTemplate object represents a parsed PRADO template. To instantiate the template
+ * for a particular control, call {@link instantiateIn($control)}, which
+ * will create and intialize all components specified in the template and
+ * set their parent as $control.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplate extends TApplicationComponent implements ITemplate
+{
+ /**
+ * '' - template comments
+ * '' - HTML comments
+ * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags
+ * '<\/?prop:([\w\.]+)\s*>' - property tags
+ * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives
+ * '<%[%#~\/\\$=\\[](.*?)%>' - expressions
+ * ')*)\s*\/>' - group subproperty tags
+ */
+ const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS';
+
+ /**
+ * Different configurations of component property/event/attribute
+ */
+ const CONFIG_DATABIND=0;
+ const CONFIG_EXPRESSION=1;
+ const CONFIG_ASSET=2;
+ const CONFIG_PARAMETER=3;
+ const CONFIG_LOCALIZATION=4;
+ const CONFIG_TEMPLATE=5;
+
+ /**
+ * @var array list of component tags and strings
+ */
+ private $_tpl=array();
+ /**
+ * @var array list of directive settings
+ */
+ private $_directive=array();
+ /**
+ * @var string context path
+ */
+ private $_contextPath;
+ /**
+ * @var string template file path (if available)
+ */
+ private $_tplFile=null;
+ /**
+ * @var integer the line number that parsing starts from (internal use)
+ */
+ private $_startingLine=0;
+ /**
+ * @var string template content to be parsed
+ */
+ private $_content;
+ /**
+ * @var boolean whether this template is a source template
+ */
+ private $_sourceTemplate=true;
+ /**
+ * @var string hash code of the template
+ */
+ private $_hashCode='';
+ private $_tplControl=null;
+ private $_includedFiles=array();
+ private $_includeAtLine=array();
+ private $_includeLines=array();
+
+
+ /**
+ * Constructor.
+ * The template will be parsed after construction.
+ * @param string the template string
+ * @param string the template context directory
+ * @param string the template file, null if no file
+ * @param integer the line number that parsing starts from (internal use)
+ * @param boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
+ {
+ $this->_sourceTemplate=$sourceTemplate;
+ $this->_contextPath=$contextPath;
+ $this->_tplFile=$tplFile;
+ $this->_startingLine=$startingLine;
+ $this->_content=$template;
+ $this->_hashCode=md5($template);
+ $this->parse($template);
+ $this->_content=null; // reset to save memory
+ }
+
+ /**
+ * @return string template file path if available, null otherwise.
+ */
+ public function getTemplateFile()
+ {
+ return $this->_tplFile;
+ }
+
+ /**
+ * @return boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function getIsSourceTemplate()
+ {
+ return $this->_sourceTemplate;
+ }
+
+ /**
+ * @return string context directory path
+ */
+ public function getContextPath()
+ {
+ return $this->_contextPath;
+ }
+
+ /**
+ * @return array name-value pairs declared in the directive
+ */
+ public function getDirective()
+ {
+ return $this->_directive;
+ }
+
+ /**
+ * @return string hash code that can be used to identify the template
+ */
+ public function getHashCode()
+ {
+ return $this->_hashCode;
+ }
+
+ /**
+ * @return array the parsed template
+ */
+ public function &getItems()
+ {
+ return $this->_tpl;
+ }
+
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the control who owns the template
+ * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control.
+ */
+ public function instantiateIn($tplControl,$parentControl=null)
+ {
+ $this->_tplControl=$tplControl;
+ if($parentControl===null)
+ $parentControl=$tplControl;
+ if(($page=$tplControl->getPage())===null)
+ $page=$this->getService()->getRequestedPage();
+ $controls=array();
+ $directChildren=array();
+ foreach($this->_tpl as $key=>$object)
+ {
+ if($object[0]===-1)
+ $parent=$parentControl;
+ else if(isset($controls[$object[0]]))
+ $parent=$controls[$object[0]];
+ else
+ continue;
+ if(isset($object[2])) // component
+ {
+ $component=Prado::createComponent($object[1]);
+ $properties=&$object[2];
+ if($component instanceof TControl)
+ {
+ if($component instanceof TOutputCache)
+ $component->setCacheKeyPrefix($this->_hashCode.$key);
+ $component->setTemplateControl($tplControl);
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ }
+ if(isset($properties['skinid']))
+ {
+ if(is_array($properties['skinid']))
+ $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
+ else
+ $component->setSkinID($properties['skinid']);
+ unset($properties['skinid']);
+ }
+
+ $component->trackViewState(false);
+
+ $component->applyStyleSheetSkin($page);
+ foreach($properties as $name=>$value)
+ $this->configureControl($component,$name,$value);
+
+ $component->trackViewState(true);
+
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ if($component->getAllowChildControls())
+ $controls[$key]=$component;
+ }
+ else if($component instanceof TComponent)
+ {
+ $controls[$key]=$component;
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ if(!$component->hasProperty('id'))
+ unset($properties['id']);
+ }
+ foreach($properties as $name=>$value)
+ $this->configureComponent($component,$name,$value);
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ }
+ }
+ else
+ {
+ if($object[1] instanceof TCompositeLiteral)
+ {
+ // need to clone a new object because the one in template is reused
+ $o=clone $object[1];
+ $o->setContainer($tplControl);
+ if($parent===$parentControl)
+ $directChildren[]=$o;
+ else
+ $parent->addParsedObject($o);
+ }
+ else
+ {
+ if($parent===$parentControl)
+ $directChildren[]=$object[1];
+ else
+ $parent->addParsedObject($object[1]);
+ }
+ }
+ }
+ // delay setting parent till now because the parent may cause
+ // the child to do lifecycle catchup which may cause problem
+ // if the child needs its own child controls.
+ foreach($directChildren as $control)
+ {
+ if($control instanceof TComponent)
+ $control->createdOnTemplate($parentControl);
+ else
+ $parentControl->addParsedObject($control);
+ }
+ }
+
+ /**
+ * Configures a property/event of a control.
+ * @param TControl control to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureControl($control,$name,$value)
+ {
+ if(strncasecmp($name,'on',2)===0) // is an event
+ $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
+ $this->configureProperty($control,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($control,$name,$value);
+ }
+
+ /**
+ * Configures a property of a non-control component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureComponent($component,$name,$value)
+ {
+ if(strpos($name,'.')===false) // is a simple property or custom attribute
+ $this->configureProperty($component,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($component,$name,$value);
+ }
+
+ /**
+ * Configures an event for a control.
+ * @param TControl control to be configured
+ * @param string event name
+ * @param string event handler
+ * @param TControl context control
+ */
+ protected function configureEvent($control,$name,$value,$contextControl)
+ {
+ if(strpos($value,'.')===false)
+ $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
+ else
+ $control->attachEventHandler($name,array($contextControl,$value));
+ }
+
+ /**
+ * Configures a simple property for a component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND:
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION:
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ {
+ $setter='set'.$name;
+ $component->$setter($this->_tplControl->evaluateExpression($value[1]));
+ }
+ break;
+ case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
+ $component->$setter($value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $setter='set'.$name;
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->$setter($url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $setter='set'.$name;
+ $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
+ $component->$setter(Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ {
+ if (substr($name,0,2)=='js')
+ if ($value and !($value instanceof TJavaScriptLiteral))
+ $value = new TJavaScriptLiteral($value);
+ $setter='set'.$name;
+ $component->$setter($value);
+ }
+ }
+
+ /**
+ * Configures a subproperty for a component.
+ * @param TComponent component to be configured
+ * @param string subproperty name
+ * @param mixed subproperty initial value
+ */
+ protected function configureSubProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND: // databinding
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION: // expression
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
+ break;
+ case self::CONFIG_TEMPLATE:
+ $component->setSubProperty($name,$value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->setSubProperty($name,$url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $component->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ $component->setSubProperty($name,$value);
+ }
+
+ /**
+ * Parses a template string.
+ *
+ * This template parser recognizes five types of data:
+ * regular string, well-formed component tags, well-formed property tags, directives, and expressions.
+ *
+ * The parsing result is returned as an array. Each array element can be of three types:
+ * - a string, 0: container index; 1: string content;
+ * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs)
+ * If a directive is found in the template, it will be parsed and can be
+ * retrieved via {@link getDirective}, which returns an array consisting of
+ * name-value pairs in the directive.
+ *
+ * Note, attribute names are treated as case-insensitive and will be turned into lower cases.
+ * Component and directive types are case-sensitive.
+ * Container index is the index to the array element that stores the container object.
+ * If an object has no container, its container index is -1.
+ *
+ * @param string the template string
+ * @throws TConfigurationException if a parsing error is encountered
+ */
+ protected function parse($input)
+ {
+ $input=$this->preprocess($input);
+ $tpl=&$this->_tpl;
+ $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ $expectPropEnd=false;
+ $textStart=0;
+ $stack=array();
+ $container=-1;
+ $matchEnd=0;
+ $c=0;
+ $this->_directive=null;
+ try
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $str=$match[0][0];
+ $matchStart=$match[0][1];
+ $matchEnd=$matchStart+strlen($str)-1;
+ if(strpos($str,'$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+ $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
+ $this->validateAttributes($type,$attributes);
+ $tpl[$c++]=array($container,$type,$attributes);
+ if($str[strlen($str)-2]!=='/') // open tag
+ {
+ $stack[] = $type;
+ $container=$c-1;
+ }
+ }
+ else if(strpos($str,' $textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"");
+
+ $name=array_pop($stack);
+ if($name!==$type)
+ {
+ $tag=$name[0]==='@' ? ' ' : "";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ $container=$tpl[$container][0];
+ }
+ else if(strpos($str,'<%@')===0) // directive
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ if(isset($tpl[0]) || $this->_directive!==null)
+ throw new TConfigurationException('template_directive_nonunique');
+ $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
+ }
+ else if(strpos($str,'<%')===0) // expression
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $literal=trim($match[5][0]);
+ if($str[2]==='=') // expression
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
+ else if($str[2]==='%') // statements
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
+ else if($str[2]==='#')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
+ else if($str[2]==='$')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
+ else if($str[2]==='~')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
+ else if($str[2]==='/')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
+ else if($str[2]==='[')
+ {
+ $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
+ }
+ }
+ else if(strpos($str,' ')===strlen($str)-2) //subproperties
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $prop=strtolower($match[6][0]);
+ $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
+ $attributes=array();
+ foreach($attrs as $name=>$value)
+ $attributes[$prop.'.'.$name]=$value;
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,$attributes);
+ foreach($attributes as $name=>$value)
+ {
+ if(isset($tpl[$container][2][$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $tpl[$container][2][$name]=$value;
+ }
+ }
+ else // regular property
+ {
+ $prop=strtolower($match[3][0]);
+ $stack[] = '@'.$prop;
+ if(!$expectPropEnd)
+ {
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $expectPropEnd=true;
+ }
+ }
+ }
+ else if(strpos($str,' ");
+ $name=array_pop($stack);
+ if($name!=='@'.$prop)
+ {
+ $tag=$name[0]==='@' ? '' : "";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
+ {
+ if($matchStart>$textStart)
+ {
+ $value=substr($input,$textStart,$matchStart-$textStart);
+ if(substr($prop,-8,8)==='template')
+ $value=$this->parseTemplateProperty($value,$textStart);
+ else
+ $value=$this->parseAttribute($value);
+ if($container>=0)
+ {
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,array($prop=>$value));
+ if(isset($tpl[$container][2][$prop]))
+ throw new TConfigurationException('template_property_duplicated',$prop);
+ $tpl[$container][2][$prop]=$value;
+ }
+ else // a property for the template control
+ $this->_directive[$prop]=$value;
+ $textStart=$matchEnd+1;
+ }
+ $expectPropEnd=false;
+ }
+ }
+ else if(strpos($str,'
- *
- * Use the {@link setClientValidationFunction ClientValidationFunction} property
- * to specify the name of the client-side validation script function associated
- * with the TCustomValidator.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCustomValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCustomValidator';
- }
-
- /**
- * @return string the name of the custom client-side script function used for validation.
- */
- public function getClientValidationFunction()
- {
- return $this->getViewState('ClientValidationFunction','');
- }
-
- /**
- * Sets the name of the custom client-side script function used for validation.
- * @param string the script function name
- */
- public function setClientValidationFunction($value)
- {
- $this->setViewState('ClientValidationFunction',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if {@link onServerValidate} returns true.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- $value = '';
- if($this->getValidationTarget()!==null)
- $value=$this->getValidationValue($this->getValidationTarget());
- return $this->onServerValidate($value);
- }
-
- /**
- * This method is invoked when the server side validation happens.
- * It will raise the OnServerValidate event.
- * The method also allows derived classes to handle the event without attaching a delegate.
- * Note The derived classes should call parent implementation
- * to ensure the OnServerValidate event is raised.
- * @param string the value to be validated
- * @return boolean whether the value is valid
- */
- public function onServerValidate($value)
- {
- $param=new TServerValidateEventParameter($value,true);
- $this->raiseEvent('OnServerValidate',$this,$param);
- return $param->getIsValid();
- }
-
- /**
- * @return TControl control to be validated. Null if no control is found.
- */
- public function getValidationTarget()
- {
- if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
- return $control;
- else if(($id=$this->getControlToValidate())!=='')
- throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
- else
- return null;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- if(($clientJs=$this->getClientValidationFunction())!=='')
- $options['ClientValidationFunction']=$clientJs;
- return $options;
- }
-
- /**
- * Only register the client-side validator if
- * {@link setClientValidationFunction ClientValidationFunction} is set.
- */
- protected function registerClientScriptValidator()
- {
- if($this->getClientValidationFunction()!=='')
- parent::registerClientScriptValidator();
- }
-}
-
-/**
- * TServerValidateEventParameter class
- *
- * TServerValidateEventParameter encapsulates the parameter data for
- * OnServerValidate event of TCustomValidator components.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TServerValidateEventParameter extends TEventParameter
-{
- /**
- * the value to be validated
- * @var string
- */
- private $_value='';
- /**
- * whether the value is valid
- * @var boolean
- */
- private $_isValid=true;
-
- /**
- * Constructor.
- * @param string property value to be validated
- * @param boolean whether the value is valid
- */
- public function __construct($value,$isValid)
- {
- $this->_value=$value;
- $this->setIsValid($isValid);
- }
-
- /**
- * @return string value to be validated
- */
- public function getValue()
- {
- return $this->_value;
- }
-
- /**
- * @return boolean whether the value is valid
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the value is valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TCustomValidator class
+ *
+ * TCustomValidator performs user-defined validation (either
+ * server-side or client-side or both) on an input component.
+ *
+ * To create a server-side validation function, provide a handler for
+ * the {@link onServerValidate OnServerValidate} event that performs the validation.
+ * The data string of the input control to validate can be accessed
+ * by {@link TServerValidateEventParameter::getValue Value} of the event parameter.
+ * The result of the validation should be stored in the
+ * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event
+ * parameter.
+ *
+ * To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:
+ *
+ *
+ *
+ * Use the {@link setClientValidationFunction ClientValidationFunction} property
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCustomValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCustomValidator';
+ }
+
+ /**
+ * @return string the name of the custom client-side script function used for validation.
+ */
+ public function getClientValidationFunction()
+ {
+ return $this->getViewState('ClientValidationFunction','');
+ }
+
+ /**
+ * Sets the name of the custom client-side script function used for validation.
+ * @param string the script function name
+ */
+ public function setClientValidationFunction($value)
+ {
+ $this->setViewState('ClientValidationFunction',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if {@link onServerValidate} returns true.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ $value = '';
+ if($this->getValidationTarget()!==null)
+ $value=$this->getValidationValue($this->getValidationTarget());
+ return $this->onServerValidate($value);
+ }
+
+ /**
+ * This method is invoked when the server side validation happens.
+ * It will raise the OnServerValidate event.
+ * The method also allows derived classes to handle the event without attaching a delegate.
+ * Note The derived classes should call parent implementation
+ * to ensure the OnServerValidate event is raised.
+ * @param string the value to be validated
+ * @return boolean whether the value is valid
+ */
+ public function onServerValidate($value)
+ {
+ $param=new TServerValidateEventParameter($value,true);
+ $this->raiseEvent('OnServerValidate',$this,$param);
+ return $param->getIsValid();
+ }
+
+ /**
+ * @return TControl control to be validated. Null if no control is found.
+ */
+ public function getValidationTarget()
+ {
+ if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
+ return $control;
+ else if(($id=$this->getControlToValidate())!=='')
+ throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
+ else
+ return null;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ if(($clientJs=$this->getClientValidationFunction())!=='')
+ $options['ClientValidationFunction']=$clientJs;
+ return $options;
+ }
+
+ /**
+ * Only register the client-side validator if
+ * {@link setClientValidationFunction ClientValidationFunction} is set.
+ */
+ protected function registerClientScriptValidator()
+ {
+ if($this->getClientValidationFunction()!=='')
+ parent::registerClientScriptValidator();
+ }
+}
+
+/**
+ * TServerValidateEventParameter class
+ *
+ * TServerValidateEventParameter encapsulates the parameter data for
+ * OnServerValidate event of TCustomValidator components.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TServerValidateEventParameter extends TEventParameter
+{
+ /**
+ * the value to be validated
+ * @var string
+ */
+ private $_value='';
+ /**
+ * whether the value is valid
+ * @var boolean
+ */
+ private $_isValid=true;
+
+ /**
+ * Constructor.
+ * @param string property value to be validated
+ * @param boolean whether the value is valid
+ */
+ public function __construct($value,$isValid)
+ {
+ $this->_value=$value;
+ $this->setIsValid($isValid);
+ }
+
+ /**
+ * @return string value to be validated
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @return boolean whether the value is valid
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the value is valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php
index 294dd416..076179fb 100644
--- a/framework/Web/UI/WebControls/TDataBoundControl.php
+++ b/framework/Web/UI/WebControls/TDataBoundControl.php
@@ -1,587 +1,587 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataSourceControl');
-Prado::using('System.Web.UI.WebControls.TDataSourceView');
-Prado::using('System.Collections.TPagedDataSource');
-
-/**
- * TDataBoundControl class.
- *
- * TDataBoundControl is the based class for controls that need to populate
- * data from data sources. It provides basic properties and methods that allow
- * the derived controls to associate with data sources and retrieve data from them.
- *
- * TBC....
- *
- * TDataBoundControl is equipped with paging capabilities. By setting
- * {@link setAllowPaging AllowPaging} to true, the input data will be paged
- * and only one page of data is actually populated into the data-bound control.
- * This saves a lot of memory when dealing with larget datasets.
- *
- * To specify the number of data items displayed on each page, set
- * the {@link setPageSize PageSize} property, and to specify which
- * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
- *
- * When the size of the original data is too big to be loaded all in the memory,
- * one can enable custom paging. In custom paging, the total number of data items
- * is specified manually via {@link setVirtualItemCount VirtualItemCount},
- * and the data source only needs to contain the current page of data. To enable
- * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataBoundControl extends TWebControl
-{
- private $_initialized=false;
- private $_dataSource=null;
- private $_requiresBindToNull=false;
- private $_requiresDataBinding=false;
- private $_prerendered=false;
- private $_currentView=null;
- private $_currentDataSource=null;
- private $_currentViewValid=false;
- private $_currentDataSourceValid=false;
- private $_currentViewIsFromDataSourceID=false;
- private $_parameters=null;
- private $_isDataBound=false;
-
- /**
- * @return Traversable data source object, defaults to null.
- */
- public function getDataSource()
- {
- return $this->_dataSource;
- }
-
- /**
- * Sets the data source object associated with the databound control.
- * The data source must implement Traversable interface.
- * If an array is given, it will be converted to xxx.
- * If a string is given, it will be converted to xxx.
- * @param Traversable|array|string data source object
- */
- public function setDataSource($value)
- {
- $this->_dataSource=$this->validateDataSource($value);
- $this->onDataSourceChanged();
- }
-
- /**
- * @return string ID path to the data source control. Defaults to empty.
- */
- public function getDataSourceID()
- {
- return $this->getViewState('DataSourceID','');
- }
-
- /**
- * @param string ID path to the data source control. The data source
- * control must be locatable via {@link TControl::findControl} call.
- */
- public function setDataSourceID($value)
- {
- $dsid=$this->getViewState('DataSourceID','');
- if($dsid!=='' && $value==='')
- $this->_requiresBindToNull=true;
- $this->setViewState('DataSourceID',$value,'');
- $this->onDataSourceChanged();
- }
-
- /**
- * @return boolean if the databound control uses the data source specified
- * by {@link setDataSourceID}, or it uses the data source object specified
- * by {@link setDataSource}.
- */
- protected function getUsingDataSourceID()
- {
- return $this->getDataSourceID()!=='';
- }
-
- /**
- * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
- * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
- */
- public function onDataSourceChanged()
- {
- $this->_currentViewValid=false;
- $this->_currentDataSourceValid=false;
- if($this->getInitialized())
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * @return boolean whether the databound control has been initialized.
- * By default, the control is initialized after its viewstate has been restored.
- */
- protected function getInitialized()
- {
- return $this->_initialized;
- }
-
- /**
- * Sets a value indicating whether the databound control is initialized.
- * If initialized, any modification to {@link setDataSource DataSource} or
- * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
- * as true.
- * @param boolean a value indicating whether the databound control is initialized.
- */
- protected function setInitialized($value)
- {
- $this->_initialized=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether databind has been invoked in the previous page request
- */
- protected function getIsDataBound()
- {
- return $this->_isDataBound;
- }
-
- /**
- * @param boolean if databind has been invoked in this page request
- */
- protected function setIsDataBound($value)
- {
- $this->_isDataBound=$value;
- }
-
- /**
- * @return boolean whether a databind call is required (by the data bound control)
- */
- protected function getRequiresDataBinding()
- {
- return $this->_requiresDataBinding;
- }
-
- /**
- * @return boolean whether paging is enabled. Defaults to false.
- */
- public function getAllowPaging()
- {
- return $this->getViewState('AllowPaging',false);
- }
-
- /**
- * @param boolean whether paging is enabled
- */
- public function setAllowPaging($value)
- {
- $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the custom paging is enabled. Defaults to false.
- */
- public function getAllowCustomPaging()
- {
- return $this->getViewState('AllowCustomPaging',false);
- }
-
- /**
- * Sets a value indicating whether the custom paging should be enabled.
- * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
- * property is used to determine the paging, and the data items in the
- * {@link setDataSource DataSource} are considered to be in the current page.
- * @param boolean whether the custom paging is enabled
- */
- public function setAllowCustomPaging($value)
- {
- $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer the number of data items on each page. Defaults to 10.
- */
- public function getPageSize()
- {
- return $this->getViewState('PageSize',10);
- }
-
- /**
- * @param integer the number of data items on each page.
- * @throws TInvalidDataValueException if the value is less than 1
- */
- public function setPageSize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
- $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
- }
-
- /**
- * @return integer number of pages of data items available
- */
- public function getPageCount()
- {
- return $this->getViewState('PageCount',1);
- }
-
- /**
- * @return integer virtual number of data items in the data source. Defaults to 0.
- * @see setAllowCustomPaging
- */
- public function getVirtualItemCount()
- {
- return $this->getViewState('VirtualItemCount',0);
- }
-
- /**
- * @param integer virtual number of data items in the data source.
- * @throws TInvalidDataValueException if the value is less than 0
- * @see setAllowCustomPaging
- */
- public function setVirtualItemCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
- $this->setViewState('VirtualItemCount',$value,0);
- }
-
- /**
- * Sets a value indicating whether a databind call is required by the data bound control.
- * If true and the control has been prerendered while it uses the data source
- * specified by {@link setDataSourceID}, a databind call will be called by this method.
- * @param boolean whether a databind call is required.
- */
- protected function setRequiresDataBinding($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- if($value && $this->_prerendered)
- {
- $this->_requiresDataBinding=true;
- $this->ensureDataBound();
- }
- else
- $this->_requiresDataBinding=$value;
- }
-
- /**
- * Ensures any pending {@link dataBind} is called.
- * This method calls {@link dataBind} if the data source is specified
- * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
- * is true.
- */
- protected function ensureDataBound()
- {
- if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
- {
- $this->dataBind();
- $this->_requiresBindToNull=false;
- }
- }
-
- /**
- * @return TPagedDataSource creates a paged data source
- */
- protected function createPagedDataSource()
- {
- $ds=new TPagedDataSource;
- $ds->setCurrentPageIndex($this->getCurrentPageIndex());
- $ds->setPageSize($this->getPageSize());
- $ds->setAllowPaging($this->getAllowPaging());
- $ds->setAllowCustomPaging($this->getAllowCustomPaging());
- $ds->setVirtualItemCount($this->getVirtualItemCount());
- return $ds;
- }
-
- /**
- * Performs databinding.
- * This method overrides the parent implementation by calling
- * {@link performSelect} which fetches data from data source and does
- * the actual binding work.
- */
- public function dataBind()
- {
- $this->setRequiresDataBinding(false);
- $this->dataBindProperties();
- $this->onDataBinding(null);
-
- if(($view=$this->getDataSourceView())!==null)
- $data=$view->select($this->getSelectParameters());
- else
- $data=null;
-
- if($data instanceof Traversable)
- {
- if($this->getAllowPaging())
- {
- $ds=$this->createPagedDataSource();
- $ds->setDataSource($data);
- $this->setViewState('PageCount',$ds->getPageCount());
- if($ds->getCurrentPageIndex()>=$ds->getPageCount())
- {
- $ds->setCurrentPageIndex($ds->getPageCount()-1);
- $this->setCurrentPageIndex($ds->getCurrentPageIndex());
- }
- $this->performDataBinding($ds);
- }
- else
- {
- $this->clearViewState('PageCount');
- $this->performDataBinding($data);
- }
- }
- $this->setIsDataBound(true);
- $this->onDataBound(null);
- }
-
- public function dataSourceViewChanged($sender,$param)
- {
- if(!$this->_ignoreDataSourceViewChanged)
- $this->setRequiresDataBinding(true);
- }
-
- protected function getDataSourceView()
- {
- if(!$this->_currentViewValid)
- {
- if($this->_currentView && $this->_currentViewIsFromDataSourceID)
- $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
- if(($dataSource=$this->determineDataSource())!==null)
- {
- if(($view=$dataSource->getView($this->getDataMember()))===null)
- throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
- if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
- $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
- $this->_currentView=$view;
- }
- else
- $this->_currentView=null;
- $this->_currentViewValid=true;
- }
- return $this->_currentView;
- }
-
- protected function determineDataSource()
- {
- if(!$this->_currentDataSourceValid)
- {
- if(($dsid=$this->getDataSourceID())!=='')
- {
- if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
- else if(!($dataSource instanceof IDataSource))
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
- else
- $this->_currentDataSource=$dataSource;
- }
- else if(($dataSource=$this->getDataSource())!==null)
- $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
- else
- $this->_currentDataSource=null;
- $this->_currentDataSourceValid=true;
- }
- return $this->_currentDataSource;
- }
-
- abstract protected function performDataBinding($data);
-
- /**
- * Raises OnDataBound event.
- * This method should be invoked after a databind is performed.
- * It is mainly used by framework and component developers.
- */
- public function onDataBound($param)
- {
- $this->raiseEvent('OnDataBound',$this,$param);
- }
-
- /**
- * Sets page's OnPreLoad event handler as {@link pagePreLoad}.
- * If viewstate is disabled and the current request is a postback,
- * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $page=$this->getPage();
- $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
- }
-
- /**
- * Sets {@link getInitialized} as true.
- * This method is invoked when page raises PreLoad event.
- * @param mixed event sender
- * @param TEventParameter event parameter
- */
- public function pagePreLoad($sender,$param)
- {
- $this->_initialized=true;
- $isPostBack=$this->getPage()->getIsPostBack();
- if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * Ensures any pending databind is performed.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onPreRender($param)
- {
- $this->_prerendered=true;
- $this->ensureDataBound();
- parent::onPreRender($param);
- }
-
- /**
- * Validates if the parameter is a valid data source.
- * If it is a string or an array, it will be converted as a TList object.
- * @param Traversable|array|string data source to be validated
- * @return Traversable the data that is traversable
- * @throws TInvalidDataTypeException if the data is neither null nor Traversable
- */
- protected function validateDataSource($value)
- {
- if(is_string($value))
- {
- $list=new TList;
- foreach(TPropertyValue::ensureArray($value) as $key=>$value)
- {
- if(is_array($value))
- $list->add($value);
- else
- $list->add(array($value,is_string($key)?$key:$value));
- }
- return $list;
- }
- else if(is_array($value))
- return new TMap($value);
- else if($value instanceof TDbDataReader) {
- // read array from TDbDataReader since it's forward-only stream and can only be traversed once
- return $value->readAll();
- }
- else if(($value instanceof Traversable) || $value===null)
- return $value;
- else
- throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
- }
-
- public function getDataMember()
- {
- return $this->getViewState('DataMember','');
- }
-
- public function setDataMember($value)
- {
- $this->setViewState('DataMember',$value,'');
- }
-
- public function getSelectParameters()
- {
- if(!$this->_parameters)
- $this->_parameters=new TDataSourceSelectParameters;
- return $this->_parameters;
- }
-}
-
-
-/**
- * TListItemType class.
- * TListItemType defines the enumerable type for the possible types
- * that databound list items could take.
- *
- * The following enumerable values are defined:
- * - Header: header item
- * - Footer: footer item
- * - Item: content item (neither header nor footer)
- * - Separator: separator between items
- * - AlternatingItem: alternating content item
- * - EditItem: content item in edit mode
- * - SelectedItem: selected content item
- * - Pager: pager
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TListItemType extends TEnumerable
-{
- const Header='Header';
- const Footer='Footer';
- const Item='Item';
- const Separator='Separator';
- const AlternatingItem='AlternatingItem';
- const EditItem='EditItem';
- const SelectedItem='SelectedItem';
- const Pager='Pager';
-}
-
-
-/**
- * IItemDataRenderer interface.
- *
- * IItemDataRenderer defines the interface that an item renderer
- * needs to implement. Besides the {@link getData Data} property, a list item
- * renderer also needs to provide {@link getItemIndex ItemIndex} and
- * {@link getItemType ItemType} property.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-interface IItemDataRenderer extends IDataRenderer
-{
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex();
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value);
-
- /**
- * @return TListItemType the item type.
- */
- public function getItemType();
-
- /**
- * @param TListItemType the item type.
- */
- public function setItemType($value);
-}
-
-?>
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataSourceControl');
+Prado::using('System.Web.UI.WebControls.TDataSourceView');
+Prado::using('System.Collections.TPagedDataSource');
+
+/**
+ * TDataBoundControl class.
+ *
+ * TDataBoundControl is the based class for controls that need to populate
+ * data from data sources. It provides basic properties and methods that allow
+ * the derived controls to associate with data sources and retrieve data from them.
+ *
+ * TBC....
+ *
+ * TDataBoundControl is equipped with paging capabilities. By setting
+ * {@link setAllowPaging AllowPaging} to true, the input data will be paged
+ * and only one page of data is actually populated into the data-bound control.
+ * This saves a lot of memory when dealing with larget datasets.
+ *
+ * To specify the number of data items displayed on each page, set
+ * the {@link setPageSize PageSize} property, and to specify which
+ * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
+ *
+ * When the size of the original data is too big to be loaded all in the memory,
+ * one can enable custom paging. In custom paging, the total number of data items
+ * is specified manually via {@link setVirtualItemCount VirtualItemCount},
+ * and the data source only needs to contain the current page of data. To enable
+ * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataBoundControl extends TWebControl
+{
+ private $_initialized=false;
+ private $_dataSource=null;
+ private $_requiresBindToNull=false;
+ private $_requiresDataBinding=false;
+ private $_prerendered=false;
+ private $_currentView=null;
+ private $_currentDataSource=null;
+ private $_currentViewValid=false;
+ private $_currentDataSourceValid=false;
+ private $_currentViewIsFromDataSourceID=false;
+ private $_parameters=null;
+ private $_isDataBound=false;
+
+ /**
+ * @return Traversable data source object, defaults to null.
+ */
+ public function getDataSource()
+ {
+ return $this->_dataSource;
+ }
+
+ /**
+ * Sets the data source object associated with the databound control.
+ * The data source must implement Traversable interface.
+ * If an array is given, it will be converted to xxx.
+ * If a string is given, it will be converted to xxx.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value)
+ {
+ $this->_dataSource=$this->validateDataSource($value);
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return string ID path to the data source control. Defaults to empty.
+ */
+ public function getDataSourceID()
+ {
+ return $this->getViewState('DataSourceID','');
+ }
+
+ /**
+ * @param string ID path to the data source control. The data source
+ * control must be locatable via {@link TControl::findControl} call.
+ */
+ public function setDataSourceID($value)
+ {
+ $dsid=$this->getViewState('DataSourceID','');
+ if($dsid!=='' && $value==='')
+ $this->_requiresBindToNull=true;
+ $this->setViewState('DataSourceID',$value,'');
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return boolean if the databound control uses the data source specified
+ * by {@link setDataSourceID}, or it uses the data source object specified
+ * by {@link setDataSource}.
+ */
+ protected function getUsingDataSourceID()
+ {
+ return $this->getDataSourceID()!=='';
+ }
+
+ /**
+ * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
+ * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
+ */
+ public function onDataSourceChanged()
+ {
+ $this->_currentViewValid=false;
+ $this->_currentDataSourceValid=false;
+ if($this->getInitialized())
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * @return boolean whether the databound control has been initialized.
+ * By default, the control is initialized after its viewstate has been restored.
+ */
+ protected function getInitialized()
+ {
+ return $this->_initialized;
+ }
+
+ /**
+ * Sets a value indicating whether the databound control is initialized.
+ * If initialized, any modification to {@link setDataSource DataSource} or
+ * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
+ * as true.
+ * @param boolean a value indicating whether the databound control is initialized.
+ */
+ protected function setInitialized($value)
+ {
+ $this->_initialized=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether databind has been invoked in the previous page request
+ */
+ protected function getIsDataBound()
+ {
+ return $this->_isDataBound;
+ }
+
+ /**
+ * @param boolean if databind has been invoked in this page request
+ */
+ protected function setIsDataBound($value)
+ {
+ $this->_isDataBound=$value;
+ }
+
+ /**
+ * @return boolean whether a databind call is required (by the data bound control)
+ */
+ protected function getRequiresDataBinding()
+ {
+ return $this->_requiresDataBinding;
+ }
+
+ /**
+ * @return boolean whether paging is enabled. Defaults to false.
+ */
+ public function getAllowPaging()
+ {
+ return $this->getViewState('AllowPaging',false);
+ }
+
+ /**
+ * @param boolean whether paging is enabled
+ */
+ public function setAllowPaging($value)
+ {
+ $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the custom paging is enabled. Defaults to false.
+ */
+ public function getAllowCustomPaging()
+ {
+ return $this->getViewState('AllowCustomPaging',false);
+ }
+
+ /**
+ * Sets a value indicating whether the custom paging should be enabled.
+ * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
+ * property is used to determine the paging, and the data items in the
+ * {@link setDataSource DataSource} are considered to be in the current page.
+ * @param boolean whether the custom paging is enabled
+ */
+ public function setAllowCustomPaging($value)
+ {
+ $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ public function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer the number of data items on each page. Defaults to 10.
+ */
+ public function getPageSize()
+ {
+ return $this->getViewState('PageSize',10);
+ }
+
+ /**
+ * @param integer the number of data items on each page.
+ * @throws TInvalidDataValueException if the value is less than 1
+ */
+ public function setPageSize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
+ $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',1);
+ }
+
+ /**
+ * @return integer virtual number of data items in the data source. Defaults to 0.
+ * @see setAllowCustomPaging
+ */
+ public function getVirtualItemCount()
+ {
+ return $this->getViewState('VirtualItemCount',0);
+ }
+
+ /**
+ * @param integer virtual number of data items in the data source.
+ * @throws TInvalidDataValueException if the value is less than 0
+ * @see setAllowCustomPaging
+ */
+ public function setVirtualItemCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
+ $this->setViewState('VirtualItemCount',$value,0);
+ }
+
+ /**
+ * Sets a value indicating whether a databind call is required by the data bound control.
+ * If true and the control has been prerendered while it uses the data source
+ * specified by {@link setDataSourceID}, a databind call will be called by this method.
+ * @param boolean whether a databind call is required.
+ */
+ protected function setRequiresDataBinding($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ if($value && $this->_prerendered)
+ {
+ $this->_requiresDataBinding=true;
+ $this->ensureDataBound();
+ }
+ else
+ $this->_requiresDataBinding=$value;
+ }
+
+ /**
+ * Ensures any pending {@link dataBind} is called.
+ * This method calls {@link dataBind} if the data source is specified
+ * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
+ * is true.
+ */
+ protected function ensureDataBound()
+ {
+ if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
+ {
+ $this->dataBind();
+ $this->_requiresBindToNull=false;
+ }
+ }
+
+ /**
+ * @return TPagedDataSource creates a paged data source
+ */
+ protected function createPagedDataSource()
+ {
+ $ds=new TPagedDataSource;
+ $ds->setCurrentPageIndex($this->getCurrentPageIndex());
+ $ds->setPageSize($this->getPageSize());
+ $ds->setAllowPaging($this->getAllowPaging());
+ $ds->setAllowCustomPaging($this->getAllowCustomPaging());
+ $ds->setVirtualItemCount($this->getVirtualItemCount());
+ return $ds;
+ }
+
+ /**
+ * Performs databinding.
+ * This method overrides the parent implementation by calling
+ * {@link performSelect} which fetches data from data source and does
+ * the actual binding work.
+ */
+ public function dataBind()
+ {
+ $this->setRequiresDataBinding(false);
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+
+ if(($view=$this->getDataSourceView())!==null)
+ $data=$view->select($this->getSelectParameters());
+ else
+ $data=null;
+
+ if($data instanceof Traversable)
+ {
+ if($this->getAllowPaging())
+ {
+ $ds=$this->createPagedDataSource();
+ $ds->setDataSource($data);
+ $this->setViewState('PageCount',$ds->getPageCount());
+ if($ds->getCurrentPageIndex()>=$ds->getPageCount())
+ {
+ $ds->setCurrentPageIndex($ds->getPageCount()-1);
+ $this->setCurrentPageIndex($ds->getCurrentPageIndex());
+ }
+ $this->performDataBinding($ds);
+ }
+ else
+ {
+ $this->clearViewState('PageCount');
+ $this->performDataBinding($data);
+ }
+ }
+ $this->setIsDataBound(true);
+ $this->onDataBound(null);
+ }
+
+ public function dataSourceViewChanged($sender,$param)
+ {
+ if(!$this->_ignoreDataSourceViewChanged)
+ $this->setRequiresDataBinding(true);
+ }
+
+ protected function getDataSourceView()
+ {
+ if(!$this->_currentViewValid)
+ {
+ if($this->_currentView && $this->_currentViewIsFromDataSourceID)
+ $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ if(($dataSource=$this->determineDataSource())!==null)
+ {
+ if(($view=$dataSource->getView($this->getDataMember()))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
+ if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
+ $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ $this->_currentView=$view;
+ }
+ else
+ $this->_currentView=null;
+ $this->_currentViewValid=true;
+ }
+ return $this->_currentView;
+ }
+
+ protected function determineDataSource()
+ {
+ if(!$this->_currentDataSourceValid)
+ {
+ if(($dsid=$this->getDataSourceID())!=='')
+ {
+ if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
+ else if(!($dataSource instanceof IDataSource))
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
+ else
+ $this->_currentDataSource=$dataSource;
+ }
+ else if(($dataSource=$this->getDataSource())!==null)
+ $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
+ else
+ $this->_currentDataSource=null;
+ $this->_currentDataSourceValid=true;
+ }
+ return $this->_currentDataSource;
+ }
+
+ abstract protected function performDataBinding($data);
+
+ /**
+ * Raises OnDataBound event.
+ * This method should be invoked after a databind is performed.
+ * It is mainly used by framework and component developers.
+ */
+ public function onDataBound($param)
+ {
+ $this->raiseEvent('OnDataBound',$this,$param);
+ }
+
+ /**
+ * Sets page's OnPreLoad event handler as {@link pagePreLoad}.
+ * If viewstate is disabled and the current request is a postback,
+ * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $page=$this->getPage();
+ $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
+ }
+
+ /**
+ * Sets {@link getInitialized} as true.
+ * This method is invoked when page raises PreLoad event.
+ * @param mixed event sender
+ * @param TEventParameter event parameter
+ */
+ public function pagePreLoad($sender,$param)
+ {
+ $this->_initialized=true;
+ $isPostBack=$this->getPage()->getIsPostBack();
+ if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * Ensures any pending databind is performed.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onPreRender($param)
+ {
+ $this->_prerendered=true;
+ $this->ensureDataBound();
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Validates if the parameter is a valid data source.
+ * If it is a string or an array, it will be converted as a TList object.
+ * @param Traversable|array|string data source to be validated
+ * @return Traversable the data that is traversable
+ * @throws TInvalidDataTypeException if the data is neither null nor Traversable
+ */
+ protected function validateDataSource($value)
+ {
+ if(is_string($value))
+ {
+ $list=new TList;
+ foreach(TPropertyValue::ensureArray($value) as $key=>$value)
+ {
+ if(is_array($value))
+ $list->add($value);
+ else
+ $list->add(array($value,is_string($key)?$key:$value));
+ }
+ return $list;
+ }
+ else if(is_array($value))
+ return new TMap($value);
+ else if($value instanceof TDbDataReader) {
+ // read array from TDbDataReader since it's forward-only stream and can only be traversed once
+ return $value->readAll();
+ }
+ else if(($value instanceof Traversable) || $value===null)
+ return $value;
+ else
+ throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
+ }
+
+ public function getDataMember()
+ {
+ return $this->getViewState('DataMember','');
+ }
+
+ public function setDataMember($value)
+ {
+ $this->setViewState('DataMember',$value,'');
+ }
+
+ public function getSelectParameters()
+ {
+ if(!$this->_parameters)
+ $this->_parameters=new TDataSourceSelectParameters;
+ return $this->_parameters;
+ }
+}
+
+
+/**
+ * TListItemType class.
+ * TListItemType defines the enumerable type for the possible types
+ * that databound list items could take.
+ *
+ * The following enumerable values are defined:
+ * - Header: header item
+ * - Footer: footer item
+ * - Item: content item (neither header nor footer)
+ * - Separator: separator between items
+ * - AlternatingItem: alternating content item
+ * - EditItem: content item in edit mode
+ * - SelectedItem: selected content item
+ * - Pager: pager
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TListItemType extends TEnumerable
+{
+ const Header='Header';
+ const Footer='Footer';
+ const Item='Item';
+ const Separator='Separator';
+ const AlternatingItem='AlternatingItem';
+ const EditItem='EditItem';
+ const SelectedItem='SelectedItem';
+ const Pager='Pager';
+}
+
+
+/**
+ * IItemDataRenderer interface.
+ *
+ * IItemDataRenderer defines the interface that an item renderer
+ * needs to implement. Besides the {@link getData Data} property, a list item
+ * renderer also needs to provide {@link getItemIndex ItemIndex} and
+ * {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+interface IItemDataRenderer extends IDataRenderer
+{
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex();
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value);
+
+ /**
+ * @return TListItemType the item type.
+ */
+ public function getItemType();
+
+ /**
+ * @param TListItemType the item type.
+ */
+ public function setItemType($value);
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TDataGrid.php b/framework/Web/UI/WebControls/TDataGrid.php
index 2af66b33..2e2c5252 100644
--- a/framework/Web/UI/WebControls/TDataGrid.php
+++ b/framework/Web/UI/WebControls/TDataGrid.php
@@ -1,2258 +1,2258 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-Prado::using('System.Collections.TPagedDataSource');
-Prado::using('System.Collections.TDummyDataSource');
-Prado::using('System.Web.UI.WebControls.TTable');
-Prado::using('System.Web.UI.WebControls.TPanel');
-Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
-
-/**
- * TDataGrid class
- *
- * TDataGrid represents a data bound and updatable grid control.
- *
- * To populate data into the datagrid, sets its {@link setDataSource DataSource}
- * to a tabular data source and call {@link dataBind()}.
- * Each row of data will be represented by an item in the {@link getItems Items}
- * collection of the datagrid.
- *
- * An item can be at one of three states: browsing, selected and edit.
- * The state determines how the item will be displayed. For example, if an item
- * is in edit state, it may be displayed as a table row with input text boxes
- * if the columns are of type {@link TBoundColumn}; and if in browsing state,
- * they are displayed as static text.
- *
- * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
- * or {@link setSelectedItemIndex SelectedItemIndex} property.
- *
- * Each datagrid item has a {@link TDataGridItem::getItemType type}
- * which tells the position and state of the item in the datalist. An item in the header
- * of the repeater is of type Header. A body item may be of either
- * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
- * index is odd or even, whether it is being selected or edited.
- *
- * A datagrid is specified with a list of columns. Each column specifies how the corresponding
- * table column will be displayed. For example, the header/footer text of that column,
- * the cells in that column, and so on. The following column types are currently
- * provided by the framework,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * There are three ways to specify columns for a datagrid.
- *
- * Automatically generated based on data source.
- * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
- * a list of columns will be automatically generated based on the schema of the data source.
- * Each column corresponds to a column of the data.
- * Specified in template. For example,
- *
- *
- *
- *
- *
- *
- *
- * Manually created in code. Columns can be manipulated via
- * the {@link setColumns Columns} property of the datagrid. For example,
- *
- * $column=new TBoundColumn;
- * $datagrid->Columns[]=$column;
- *
- *
- *
- * Note, automatically generated columns cannot be accessed via
- * the {@link getColumns Columns} property.
- *
- * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
- * is set to true, a column with nonempty {@link setSortExpression SortExpression}
- * will have its header text displayed as a clickable link button.
- * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
- * event. You can respond to this event, sort the data source according
- * to the event parameter, and then invoke {@link databind()} on the datagrid
- * to show to end users the sorted data.
- *
- * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
- * is set to true, a pager will be displayed on top and/or bottom of the table.
- * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
- * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
- * event. You can respond to this event, specify the page to be displayed by
- * setting {@link setCurrentPageIndex CurrentPageIndex} property,
- * and then invoke {@link databind()} on the datagrid to show to end users
- * a new page of data.
- *
- * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
- * datasource. The number of pages {@link getPageCount PageCount} is calculated based
- * the item number and the {@link setPageSize PageSize} property.
- * The datagrid will manage which section of the data source to be displayed
- * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
- * The second approach calculates the page number based on the
- * {@link setVirtualItemCount VirtualItemCount} property and
- * the {@link setPageSize PageSize} property. The datagrid will always
- * display from the beginning of the datasource up to the number of
- * {@link setPageSize PageSize} data items. This approach is especially
- * useful when the datasource may contain too many data items to be managed by
- * the datagrid efficiently.
- *
- * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
- * event, the event will be bubbled up to the datagrid control.
- * If the event's command name is recognizable by the datagrid control,
- * a corresponding item event will be raised. The following item events will be
- * raised upon a specific command:
- * - OnEditCommand, if CommandName=edit
- * - OnCancelCommand, if CommandName=cancel
- * - OnSelectCommand, if CommandName=select
- * - OnDeleteCommand, if CommandName=delete
- * - OnUpdateCommand, if CommandName=update
- * - onPageIndexChanged, if CommandName=page
- * - OnSortCommand, if CommandName=sort
- * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
- * the above specific command events.
- *
- * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
- * every newly created datagrid item. You can respond to this event to customize
- * the content or style of the newly created item.
- *
- * Note, the data bound to the datagrid are reset to null after databinding.
- * There are several ways to access the data associated with a datagrid row:
- * - Access the data in {@link onItemDataBound OnItemDataBound} event
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datagrid row and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the data in viewstate and get it back during postbacks.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGrid extends TBaseDataList implements INamingContainer
-{
- /**
- * datagrid item types
- * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
- */
- const IT_HEADER='Header';
- const IT_FOOTER='Footer';
- const IT_ITEM='Item';
- const IT_SEPARATOR='Separator';
- const IT_ALTERNATINGITEM='AlternatingItem';
- const IT_EDITITEM='EditItem';
- const IT_SELECTEDITEM='SelectedItem';
- const IT_PAGER='Pager';
-
- /**
- * Command name that TDataGrid understands.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
- const CMD_SORT='Sort';
- const CMD_PAGE='Page';
- const CMD_PAGE_NEXT='Next';
- const CMD_PAGE_PREV='Previous';
- const CMD_PAGE_FIRST='First';
- const CMD_PAGE_LAST='Last';
-
- /**
- * @var TDataGridColumnCollection manually created column collection
- */
- private $_columns=null;
- /**
- * @var TDataGridColumnCollection automatically created column collection
- */
- private $_autoColumns=null;
- /**
- * @var TList all columns including both manually and automatically created columns
- */
- private $_allColumns=null;
- /**
- * @var TDataGridItemCollection datagrid item collection
- */
- private $_items=null;
- /**
- * @var TDataGridItem header item
- */
- private $_header=null;
- /**
- * @var TDataGridItem footer item
- */
- private $_footer=null;
- /**
- * @var TPagedDataSource paged data source object
- */
- private $_pagedDataSource=null;
- private $_topPager=null;
- private $_bottomPager=null;
- /**
- * @var ITemplate template used when empty data is bounded
- */
- private $_emptyTemplate=null;
- /**
- * @var boolean whether empty template is effective
- */
- private $_useEmptyTemplate=false;
-
- /**
- * @return string tag name (table) of the datagrid
- */
- protected function getTagName()
- {
- return 'table';
- }
-
- /**
- * @return string Name of the class used in AutoGenerateColumns mode
- */
- protected function getAutoGenerateColumnName()
- {
- return 'TBoundColumn';
- }
-
- /**
- * Adds objects parsed in template to datagrid.
- * Datagrid columns are added into {@link getColumns Columns} collection.
- * @param mixed object parsed in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TDataGridColumn)
- $this->getColumns()->add($object);
- else
- parent::addParsedObject($object); // this is needed by EmptyTemplate
- }
-
- /**
- * @return TDataGridColumnCollection manually specified datagrid columns
- */
- public function getColumns()
- {
- if(!$this->_columns)
- $this->_columns=new TDataGridColumnCollection($this);
- return $this->_columns;
- }
-
- /**
- * @return TDataGridColumnCollection automatically generated datagrid columns
- */
- public function getAutoColumns()
- {
- if(!$this->_autoColumns)
- $this->_autoColumns=new TDataGridColumnCollection($this);
- return $this->_autoColumns;
- }
-
- /**
- * @return TDataGridItemCollection datagrid item collection
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataGridItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by datagrid.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return string the URL of the background image for the datagrid
- */
- public function getBackImageUrl()
- {
- return $this->getStyle()->getBackImageUrl();
- }
-
- /**
- * @param string the URL of the background image for the datagrid
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * @return TTableItemStyle the style for every item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TDataGridPagerStyle the style for pager
- */
- public function getPagerStyle()
- {
- if(($style=$this->getViewState('PagerStyle',null))===null)
- {
- $style=new TDataGridPagerStyle;
- $this->setViewState('PagerStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for thead element, if any
- * @since 3.1.1
- */
- public function getTableHeadStyle()
- {
- if(($style=$this->getViewState('TableHeadStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableHeadStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tbody element, if any
- * @since 3.1.1
- */
- public function getTableBodyStyle()
- {
- if(($style=$this->getViewState('TableBodyStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableBodyStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tfoot element, if any
- * @since 3.1.1
- */
- public function getTableFootStyle()
- {
- if(($style=$this->getViewState('TableFootStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableFootStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string caption for the datagrid
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string caption for the datagrid
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',$value,'');
- }
-
- /**
- * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
- }
-
- /**
- * @param TTableCaptionAlign datagrid caption alignment. Valid values include
- */
- public function setCaptionAlign($value)
- {
- $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
- }
-
- /**
- * @return TDataGridItem the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TDataGridItem the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
- */
- public function getTopPager()
- {
- return $this->_topPager;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
- */
- public function getBottomPager()
- {
- return $this->_bottomPager;
- }
-
- /**
- * @return TDataGridItem the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TDataGridItem the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return boolean whether sorting is enabled. Defaults to false.
- */
- public function getAllowSorting()
- {
- return $this->getViewState('AllowSorting',false);
- }
-
- /**
- * @param boolean whether sorting is enabled
- */
- public function setAllowSorting($value)
- {
- $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
- */
- public function getAutoGenerateColumns()
- {
- return $this->getViewState('AutoGenerateColumns',true);
- }
-
- /**
- * @param boolean whether datagrid columns should be automatically generated
- */
- public function setAutoGenerateColumns($value)
- {
- $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the header should be displayed. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether the header should be displayed
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be displayed. Defaults to false.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',false);
- }
-
- /**
- * @param boolean whether the footer should be displayed
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datagrid
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datagrid
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * {@link TDataGridItem} child controls.
- * If the event parameter is {@link TDataGridCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataGridCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- $this->setSelectedItemIndex($param->getItem()->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_SORT)===0)
- {
- $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE)===0)
- {
- $p=$param->getCommandParameter();
- if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
- $pageIndex=$this->getCurrentPageIndex()+1;
- else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
- $pageIndex=$this->getCurrentPageIndex()-1;
- else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
- $pageIndex=0;
- else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
- $pageIndex=$this->getPageCount()-1;
- else
- $pageIndex=TPropertyValue::ensureInteger($p)-1;
- $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Raises OnCancelCommand event.
- * This method is invoked when a button control raises OnCommand event
- * with cancel command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Raises OnDeleteCommand event.
- * This method is invoked when a button control raises OnCommand event
- * with delete command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises OnEditCommand event.
- * This method is invoked when a button control raises OnCommand event
- * with edit command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises OnItemCommand event.
- * This method is invoked when a button control raises OnCommand event.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises OnSortCommand event.
- * This method is invoked when a button control raises OnCommand event
- * with sort command name.
- * @param TDataGridSortCommandEventParameter event parameter
- */
- public function onSortCommand($param)
- {
- $this->raiseEvent('OnSortCommand',$this,$param);
- }
-
- /**
- * Raises OnUpdateCommand event.
- * This method is invoked when a button control raises OnCommand event
- * with update command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises OnItemCreated event.
- * This method is invoked right after a datagrid item is created and before
- * added to page hierarchy.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises OnPagerCreated event.
- * This method is invoked right after a datagrid pager is created and before
- * added to page hierarchy.
- * @param TDataGridPagerEventParameter event parameter
- */
- public function onPagerCreated($param)
- {
- $this->raiseEvent('OnPagerCreated',$this,$param);
- }
-
- /**
- * Raises OnItemDataBound event.
- * This method is invoked for each datagrid item after it performs
- * databinding.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises OnPageIndexChanged event.
- * This method is invoked when current page is changed.
- * @param TDataGridPageChangedEventParameter event parameter
- */
- public function onPageIndexChanged($param)
- {
- $this->raiseEvent('OnPageIndexChanged',$this,$param);
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if(!$this->getEnableViewState(true))
- return;
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- if($this->_autoColumns)
- {
- $state=array();
- foreach($this->_autoColumns as $column)
- $state[]=$column->saveState();
- $this->setViewState('AutoColumns',$state,array());
- }
- else
- $this->clearViewState('AutoColumns');
- if($this->_columns)
- {
- $state=array();
- foreach($this->_columns as $column)
- $state[]=$column->saveState();
- $this->setViewState('Columns',$state,array());
- }
- else
- $this->clearViewState('Columns');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getEnableViewState(true))
- return;
- if(!$this->getIsDataBound())
- {
- $state=$this->getViewState('AutoColumns',array());
- if(!empty($state))
- {
- $this->_autoColumns=new TDataGridColumnCollection($this);
- foreach($state as $st)
- {
- $column=new $this->AutoGenerateColumnName;
- $column->loadState($st);
- $this->_autoColumns->add($column);
- }
- }
- else
- $this->_autoColumns=null;
- $state=$this->getViewState('Columns',array());
- if($this->_columns && $this->_columns->getCount()===count($state))
- {
- $i=0;
- foreach($this->_columns as $column)
- {
- $column->loadState($state[$i]);
- $i++;
- }
- }
- $this->restoreGridFromViewState();
- }
- }
-
- /**
- * Clears up all items in the datagrid.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- $this->_topPager=null;
- $this->_bottomPager=null;
- $this->_useEmptyTemplate=false;
- }
-
- /**
- * Restores datagrid content from viewstate.
- */
- protected function restoreGridFromViewState()
- {
- $this->reset();
-
- $allowPaging=$this->getAllowPaging();
-
- $itemCount=$this->getViewState('ItemCount',0);
- $dsIndex=$this->getViewState('DataSourceIndex',0);
-
- $columns=new TList($this->getColumns());
- $columns->mergeWith($this->_autoColumns);
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- for($index=0;$index<$itemCount;++$index)
- {
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- }
- }
-
- /**
- * Performs databinding to populate datagrid items from data source.
- * This method is invoked by {@link dataBind()}.
- * You may override this function to provide your own way of data population.
- * @param Traversable the bound data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
-
- // get all columns
- if($this->getAutoGenerateColumns())
- {
- $columns=new TList($this->getColumns());
- $autoColumns=$this->createAutoColumns($data);
- $columns->mergeWith($autoColumns);
- }
- else
- $columns=$this->getColumns();
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- $index=0;
- $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
- $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
- $this->setViewState('DataSourceIndex',$dsIndex,0);
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$row)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($row,$keyField));
- else
- $keys->add($key);
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
- $index++;
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- $this->setViewState('ItemCount',$index,0);
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- $this->dataBindChildren();
- }
- }
-
- /**
- * Merges consecutive cells who have the same text.
- * @since 3.1.1
- */
- private function groupCells()
- {
- if(($columns=$this->_allColumns)===null)
- return;
- $items=$this->getItems();
- foreach($columns as $id=>$column)
- {
- if(!$column->getEnableCellGrouping())
- continue;
- $prevCell=null;
- $prevCellText=null;
- foreach($items as $item)
- {
- $itemType=$item->getItemType();
- $cell=$item->getCells()->itemAt($id);
- if(!$cell->getVisible())
- continue;
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- if(($cellText=$this->getCellText($cell))==='')
- {
- $prevCell=null;
- $prevCellText=null;
- continue;
- }
- if($prevCell===null || $prevCellText!==$cellText)
- {
- $prevCell=$cell;
- $prevCellText=$cellText;
- }
- else
- {
- if(($rowSpan=$prevCell->getRowSpan())===0)
- $rowSpan=1;
- $prevCell->setRowSpan($rowSpan+1);
- $cell->setVisible(false);
- }
- }
- }
- }
- }
-
- private function getCellText($cell)
- {
- if(($data=$cell->getText())==='' && $cell->getHasControls())
- {
- $controls=$cell->getControls();
- foreach($controls as $control)
- {
- if($control instanceof IDataRenderer)
- return $control->getData();
- }
- }
- return $data;
- }
-
- /**
- * Creates a datagrid item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TDataGridItem created data list item
- */
- protected function createItem($itemIndex,$dataSourceIndex,$itemType)
- {
- return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
- }
-
- private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
- {
- $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
- $this->initializeItem($item,$columns);
- $param=new TDataGridItemEventParameter($item);
- if($dataBind)
- {
- $item->setDataItem($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- }
- else
- {
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- }
- return $item;
- }
-
- /**
- * Initializes a datagrid item and cells inside it
- * @param TDataGrid datagrid item to be initialized
- * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
- */
- protected function initializeItem($item,$columns)
- {
- $cells=$item->getCells();
- $itemType=$item->getItemType();
- $index=0;
- foreach($columns as $column)
- {
- if($itemType===TListItemType::Header)
- $cell=new TTableHeaderCell;
- else
- $cell=new TTableCell;
- if(($id=$column->getID())!=='')
- $item->registerObject($id,$cell);
- $cells->add($cell);
- $column->initializeCell($cell,$index,$itemType);
- $index++;
- }
- }
-
- protected function createPager()
- {
- $pager=new TDataGridPager($this);
- $this->buildPager($pager);
- $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
- $this->getControls()->add($pager);
- return $pager;
- }
-
- /**
- * Builds the pager content based on pager style.
- * @param TDataGridPager the container for the pager
- */
- protected function buildPager($pager)
- {
- switch($this->getPagerStyle()->getMode())
- {
- case TDataGridPagerMode::NextPrev:
- $this->buildNextPrevPager($pager);
- break;
- case TDataGridPagerMode::Numeric:
- $this->buildNumericPager($pager);
- break;
- }
- }
-
- /**
- * Creates a pager button.
- * Depending on the button type, a TLinkButton or a TButton may be created.
- * If it is enabled (clickable), its command name and parameter will also be set.
- * Derived classes may override this method to create additional types of buttons, such as TImageButton.
- * @param mixed the container pager instance of TActiveDatagridPager
- * @param string button type, either LinkButton or PushButton
- * @param boolean whether the button should be enabled
- * @param string caption of the button
- * @param string CommandName corresponding to the OnCommand event of the button
- * @param string CommandParameter corresponding to the OnCommand event of the button
- * @return mixed the button instance
- */
- protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
- {
- if($buttonType===TDataGridPagerButtonType::LinkButton)
- {
- if($enabled)
- $button=new TLinkButton;
- else
- {
- $button=new TLabel;
- $button->setText($text);
- return $button;
- }
- }
- else
- {
- $button=new TButton;
- if(!$enabled)
- $button->setEnabled(false);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCommandParameter($commandParameter);
- $button->setCausesValidation(false);
- return $button;
- }
-
- /**
- * Builds a next-prev pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNextPrevPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $currentPageIndex=$this->getCurrentPageIndex();
- if($currentPageIndex===0)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- $controls->add("\n");
- }
-
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
- $controls->add($label);
- }
- else
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
-
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
- $controls->add($button);
- }
- $controls->add("\n");
- if($currentPageIndex===$this->getPageCount()-1)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
- $controls->add($label);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- }
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a numeric pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNumericPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $pageCount=$this->getPageCount();
- $pageIndex=$this->getCurrentPageIndex()+1;
- $maxButtonCount=$style->getPageButtonCount();
- $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
- $startPageIndex=1;
- $endPageIndex=$buttonCount;
- if($pageIndex>$endPageIndex)
- {
- $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
- if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
- $endPageIndex=$pageCount;
- if($endPageIndex-$startPageIndex+1<$maxButtonCount)
- {
- if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
- $startPageIndex=1;
- }
- }
-
- if($startPageIndex>1)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
- $prevPageIndex=$startPageIndex-1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
- $controls->add($button);
- $controls->add("\n");
- }
-
- for($i=$startPageIndex;$i<=$endPageIndex;++$i)
- {
- if($i===$pageIndex)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
- $controls->add($label);
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
- $controls->add($button);
- }
- if($i<$endPageIndex)
- $controls->add("\n");
- }
-
- if($pageCount>$endPageIndex)
- {
- $controls->add("\n");
- $nextPageIndex=$endPageIndex+1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Automatically generates datagrid columns based on datasource schema
- * @param Traversable data source bound to the datagrid
- * @return TDataGridColumnCollection
- */
- protected function createAutoColumns($dataSource)
- {
- if(!$dataSource)
- return null;
- $autoColumns=$this->getAutoColumns();
- $autoColumns->clear();
- foreach($dataSource as $row)
- {
- foreach($row as $key=>$value)
- {
- $column=new $this->AutoGenerateColumnName;
- if(is_string($key))
- {
- $column->setHeaderText($key);
- $column->setDataField($key);
- $column->setSortExpression($key);
- $autoColumns->add($column);
- }
- else
- {
- $column->setHeaderText(TListItemType::Item);
- $column->setDataField($key);
- $column->setSortExpression(TListItemType::Item);
- $autoColumns->add($column);
- }
- }
- break;
- }
- return $autoColumns;
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- $headerStyle=$this->getViewState('HeaderStyle',null);
- $footerStyle=$this->getViewState('FooterStyle',null);
- $pagerStyle=$this->getViewState('PagerStyle',null);
- $separatorStyle=$this->getViewState('SeparatorStyle',null);
-
- foreach($this->getControls() as $index=>$item)
- {
- if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
- continue;
- $itemType=$item->getItemType();
- switch($itemType)
- {
- case TListItemType::Header:
- if($headerStyle)
- $item->getStyle()->mergeWith($headerStyle);
- if(!$this->getShowHeader())
- $item->setVisible(false);
- break;
- case TListItemType::Footer:
- if($footerStyle)
- $item->getStyle()->mergeWith($footerStyle);
- if(!$this->getShowFooter())
- $item->setVisible(false);
- break;
- case TListItemType::Separator:
- if($separatorStyle)
- $item->getStyle()->mergeWith($separatorStyle);
- break;
- case TListItemType::Item:
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- break;
- case TListItemType::AlternatingItem:
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- break;
- case TListItemType::SelectedItem:
- if($selectedItemStyle)
- $item->getStyle()->mergeWith($selectedItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::EditItem:
- if($editItemStyle)
- $item->getStyle()->mergeWith($editItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::Pager:
- if($pagerStyle)
- {
- $item->getStyle()->mergeWith($pagerStyle);
- if($index===0)
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- else
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- }
- break;
- default:
- break;
- }
- if($this->_columns && $itemType!==TListItemType::Pager)
- {
- $n=$this->_columns->getCount();
- $cells=$item->getCells();
- for($i=0;$i<$n;++$i)
- {
- $cell=$cells->itemAt($i);
- $column=$this->_columns->itemAt($i);
- if(!$column->getVisible())
- $cell->setVisible(false);
- else
- {
- if($itemType===TListItemType::Header)
- $style=$column->getHeaderStyle(false);
- else if($itemType===TListItemType::Footer)
- $style=$column->getFooterStyle(false);
- else
- $style=$column->getItemStyle(false);
- if($style!==null)
- $cell->getStyle()->mergeWith($style);
- }
- }
- }
- }
- }
-
- /**
- * Renders the openning tag for the datagrid control which will render table caption if present.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($caption=$this->getCaption())!=='')
- {
- if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
- $writer->addAttribute('align',strtolower($align));
- $writer->renderBeginTag('caption');
- $writer->write($caption);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the datagrid.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- $this->groupCells();
- if($this->_useEmptyTemplate)
- {
- $control=new TWebControl;
- $control->setID($this->getClientID());
- $control->copyBaseAttributes($this);
- if($this->getHasStyle())
- $control->getStyle()->copyFrom($this->getStyle());
- $control->renderBeginTag($writer);
- $this->renderContents($writer);
- $control->renderEndTag($writer);
- }
- else if($this->getViewState('ItemCount',0)>0)
- {
- $this->applyItemStyles();
- if($this->_topPager)
- {
- $this->_topPager->renderControl($writer);
- $writer->writeLine();
- }
- $this->renderTable($writer);
- if($this->_bottomPager)
- {
- $writer->writeLine();
- $this->_bottomPager->renderControl($writer);
- }
- }
- }
- }
-
- /**
- * Renders the tabular data.
- * @param THtmlWriter writer
- */
- protected function renderTable($writer)
- {
- $this->renderBeginTag($writer);
- if($this->_header && $this->_header->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableHeadStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('thead');
- $this->_header->render($writer);
- $writer->renderEndTag();
- }
- $writer->writeLine();
- if($style=$this->getViewState('TableBodyStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tbody');
- foreach($this->getItems() as $item)
- $item->renderControl($writer);
- $writer->renderEndTag();
-
- if($this->_footer && $this->_footer->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableFootStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tfoot');
- $this->_footer->render($writer);
- $writer->renderEndTag();
- }
-
- $writer->writeLine();
- $this->renderEndTag($writer);
- }
-}
-
-/**
- * TDataGridItemEventParameter class
- *
- * TDataGridItemEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemEventParameter extends TEventParameter
-{
- /**
- * The TDataGridItem control responsible for the event.
- * @var TDataGridItem
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item related with the corresponding event
- */
- public function __construct(TDataGridItem $item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TDataGridItem datagrid item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataGridPagerEventParameter class
- *
- * TDataGridPagerEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
- * The {@link getPager Pager} property indicates the datagrid pager related with the event.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerEventParameter extends TEventParameter
-{
- /**
- * The TDataGridPager control responsible for the event.
- * @var TDataGridPager
- */
- protected $_pager=null;
-
- /**
- * Constructor.
- * @param TDataGridPager datagrid pager related with the corresponding event
- */
- public function __construct(TDataGridPager $pager)
- {
- $this->_pager=$pager;
- }
-
- /**
- * @return TDataGridPager datagrid pager related with the corresponding event
- */
- public function getPager()
- {
- return $this->_pager;
- }
-}
-
-/**
- * TDataGridCommandEventParameter class
- *
- * TDataGridCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TDataGridItem the TDataGridItem control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the Command event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TDataGridItem the TDataGridItem control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the Command event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataGridSortCommandEventParameter class
- *
- * TDataGridSortCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
- * gives the sort expression carried with the sort command.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridSortCommandEventParameter extends TEventParameter
-{
- /**
- * @var string sort expression
- */
- private $_sortExpression='';
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the OnCommand event.
- * @param TDataGridCommandEventParameter command event parameter
- */
- public function __construct($source,TDataGridCommandEventParameter $param)
- {
- $this->_source=$source;
- $this->_sortExpression=$param->getCommandParameter();
- }
-
- /**
- * @return TControl the control originally raises the OnCommand event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return string sort expression
- */
- public function getSortExpression()
- {
- return $this->_sortExpression;
- }
-}
-
-/**
- * TDataGridPageChangedEventParameter class
- *
- * TDataGridPageChangedEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
- * returns the new page index carried with the page command.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPageChangedEventParameter extends TEventParameter
-{
- /**
- * @var integer new page index
- */
- private $_newIndex;
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the OnCommand event.
- * @param integer new page index
- */
- public function __construct($source,$newPageIndex)
- {
- $this->_source=$source;
- $this->_newIndex=$newPageIndex;
- }
-
- /**
- * @return TControl the control originally raises the OnCommand event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return integer new page index
- */
- public function getNewPageIndex()
- {
- return $this->_newIndex;
- }
-}
-
-/**
- * TDataGridItem class
- *
- * A TDataGridItem control represents an item in the {@link TDataGrid} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
- * gives the index of the item from the bound data source.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItem extends TTableRow implements INamingContainer
-{
- /**
- * @var integer index of the data item in the Items collection of datagrid
- */
- private $_itemIndex='';
- /**
- * @var integer index of the item from the bound data source
- */
- private $_dataSourceIndex=0;
- /**
- * type of the TDataGridItem
- * @var string
- */
- private $_itemType='';
- /**
- * value of the data item
- * @var mixed
- */
- private $_data=null;
-
- /**
- * Constructor.
- * @param integer zero-based index of the item in the item collection of datagrid
- * @param TListItemType item type
- */
- public function __construct($itemIndex,$dataSourceIndex,$itemType)
- {
- $this->_itemIndex=$itemIndex;
- $this->_dataSourceIndex=$dataSourceIndex;
- $this->setItemType($itemType);
- if($itemType===TListItemType::Header)
- $this->setTableSection(TTableRowSection::Header);
- else if($itemType===TListItemType::Footer)
- $this->setTableSection(TTableRowSection::Footer);
- }
-
- /**
- * @return TListItemType item type.
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datagrid
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * @return integer the index of the datagrid item from the bound data source
- */
- public function getDataSourceIndex()
- {
- return $this->_dataSourceIndex;
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for OnCommand event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-
-/**
- * TDataGridPager class.
- *
- * TDataGridPager represents a datagrid pager.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPager extends TPanel implements INamingContainer
-{
- private $_dataGrid;
-
- /**
- * Constructor.
- * @param TDataGrid datagrid object
- */
- public function __construct($dataGrid)
- {
- $this->_dataGrid=$dataGrid;
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for OnCommand event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * @return TDataGrid the datagrid owning this pager
- */
- public function getDataGrid()
- {
- return $this->_dataGrid;
- }
-
- /**
- * @return string item type.
- */
- public function getItemType()
- {
- return TListItemType::Pager;
- }
-}
-
-
-/**
- * TDataGridItemCollection class.
- *
- * TDataGridItemCollection represents a collection of data grid items.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TDataGridItem.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridItem)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
- }
-}
-
-/**
- * TDataGridColumnCollection class.
- *
- * TDataGridColumnCollection represents a collection of data grid columns.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridColumnCollection extends TList
-{
- /**
- * the control that owns this collection.
- * @var TControl
- */
- private $_o;
-
- /**
- * Constructor.
- * @param TDataGrid the control that owns this collection.
- */
- public function __construct(TDataGrid $owner)
- {
- $this->_o=$owner;
- }
-
- /**
- * @return TDataGrid the control that owns this collection.
- */
- protected function getOwner()
- {
- return $this->_o;
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TDataGridColumn.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridColumn)
- {
- $item->setOwner($this->_o);
- parent::insertAt($index,$item);
- }
- else
- throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
- }
-}
-
-/**
- * TDataGridPagerMode class.
- * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
- *
- * The following enumerable values are defined:
- * - NextPrev: pager buttons are displayed as next and previous pages
- * - Numeric: pager buttons are displayed as numeric page numbers
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerMode extends TEnumerable
-{
- const NextPrev='NextPrev';
- const Numeric='Numeric';
-}
-
-
-/**
- * TDataGridPagerButtonType class.
- * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form submit buttons
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerButtonType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
-}
-
-
-/**
- * TDataGridPagerPosition class.
- * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
- *
- * The following enumerable values are defined:
- * - Bottom: pager appears only at the bottom of the data grid.
- * - Top: pager appears only at the top of the data grid.
- * - TopAndBottom: pager appears on both top and bottom of the data grid.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerPosition extends TEnumerable
-{
- const Bottom='Bottom';
- const Top='Top';
- const TopAndBottom='TopAndBottom';
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+Prado::using('System.Collections.TPagedDataSource');
+Prado::using('System.Collections.TDummyDataSource');
+Prado::using('System.Web.UI.WebControls.TTable');
+Prado::using('System.Web.UI.WebControls.TPanel');
+Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
+
+/**
+ * TDataGrid class
+ *
+ * TDataGrid represents a data bound and updatable grid control.
+ *
+ * To populate data into the datagrid, sets its {@link setDataSource DataSource}
+ * to a tabular data source and call {@link dataBind()}.
+ * Each row of data will be represented by an item in the {@link getItems Items}
+ * collection of the datagrid.
+ *
+ * An item can be at one of three states: browsing, selected and edit.
+ * The state determines how the item will be displayed. For example, if an item
+ * is in edit state, it may be displayed as a table row with input text boxes
+ * if the columns are of type {@link TBoundColumn}; and if in browsing state,
+ * they are displayed as static text.
+ *
+ * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
+ * or {@link setSelectedItemIndex SelectedItemIndex} property.
+ *
+ * Each datagrid item has a {@link TDataGridItem::getItemType type}
+ * which tells the position and state of the item in the datalist. An item in the header
+ * of the repeater is of type Header. A body item may be of either
+ * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
+ * index is odd or even, whether it is being selected or edited.
+ *
+ * A datagrid is specified with a list of columns. Each column specifies how the corresponding
+ * table column will be displayed. For example, the header/footer text of that column,
+ * the cells in that column, and so on. The following column types are currently
+ * provided by the framework,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * There are three ways to specify columns for a datagrid.
+ *
+ * Automatically generated based on data source.
+ * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
+ * a list of columns will be automatically generated based on the schema of the data source.
+ * Each column corresponds to a column of the data.
+ * Specified in template. For example,
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Manually created in code. Columns can be manipulated via
+ * the {@link setColumns Columns} property of the datagrid. For example,
+ *
+ * $column=new TBoundColumn;
+ * $datagrid->Columns[]=$column;
+ *
+ *
+ *
+ * Note, automatically generated columns cannot be accessed via
+ * the {@link getColumns Columns} property.
+ *
+ * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
+ * is set to true, a column with nonempty {@link setSortExpression SortExpression}
+ * will have its header text displayed as a clickable link button.
+ * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
+ * event. You can respond to this event, sort the data source according
+ * to the event parameter, and then invoke {@link databind()} on the datagrid
+ * to show to end users the sorted data.
+ *
+ * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
+ * is set to true, a pager will be displayed on top and/or bottom of the table.
+ * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
+ * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
+ * event. You can respond to this event, specify the page to be displayed by
+ * setting {@link setCurrentPageIndex CurrentPageIndex} property,
+ * and then invoke {@link databind()} on the datagrid to show to end users
+ * a new page of data.
+ *
+ * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
+ * datasource. The number of pages {@link getPageCount PageCount} is calculated based
+ * the item number and the {@link setPageSize PageSize} property.
+ * The datagrid will manage which section of the data source to be displayed
+ * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
+ * The second approach calculates the page number based on the
+ * {@link setVirtualItemCount VirtualItemCount} property and
+ * the {@link setPageSize PageSize} property. The datagrid will always
+ * display from the beginning of the datasource up to the number of
+ * {@link setPageSize PageSize} data items. This approach is especially
+ * useful when the datasource may contain too many data items to be managed by
+ * the datagrid efficiently.
+ *
+ * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
+ * event, the event will be bubbled up to the datagrid control.
+ * If the event's command name is recognizable by the datagrid control,
+ * a corresponding item event will be raised. The following item events will be
+ * raised upon a specific command:
+ * - OnEditCommand, if CommandName=edit
+ * - OnCancelCommand, if CommandName=cancel
+ * - OnSelectCommand, if CommandName=select
+ * - OnDeleteCommand, if CommandName=delete
+ * - OnUpdateCommand, if CommandName=update
+ * - onPageIndexChanged, if CommandName=page
+ * - OnSortCommand, if CommandName=sort
+ * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
+ * the above specific command events.
+ *
+ * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
+ * every newly created datagrid item. You can respond to this event to customize
+ * the content or style of the newly created item.
+ *
+ * Note, the data bound to the datagrid are reset to null after databinding.
+ * There are several ways to access the data associated with a datagrid row:
+ * - Access the data in {@link onItemDataBound OnItemDataBound} event
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datagrid row and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the data in viewstate and get it back during postbacks.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGrid extends TBaseDataList implements INamingContainer
+{
+ /**
+ * datagrid item types
+ * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
+ */
+ const IT_HEADER='Header';
+ const IT_FOOTER='Footer';
+ const IT_ITEM='Item';
+ const IT_SEPARATOR='Separator';
+ const IT_ALTERNATINGITEM='AlternatingItem';
+ const IT_EDITITEM='EditItem';
+ const IT_SELECTEDITEM='SelectedItem';
+ const IT_PAGER='Pager';
+
+ /**
+ * Command name that TDataGrid understands.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+ const CMD_SORT='Sort';
+ const CMD_PAGE='Page';
+ const CMD_PAGE_NEXT='Next';
+ const CMD_PAGE_PREV='Previous';
+ const CMD_PAGE_FIRST='First';
+ const CMD_PAGE_LAST='Last';
+
+ /**
+ * @var TDataGridColumnCollection manually created column collection
+ */
+ private $_columns=null;
+ /**
+ * @var TDataGridColumnCollection automatically created column collection
+ */
+ private $_autoColumns=null;
+ /**
+ * @var TList all columns including both manually and automatically created columns
+ */
+ private $_allColumns=null;
+ /**
+ * @var TDataGridItemCollection datagrid item collection
+ */
+ private $_items=null;
+ /**
+ * @var TDataGridItem header item
+ */
+ private $_header=null;
+ /**
+ * @var TDataGridItem footer item
+ */
+ private $_footer=null;
+ /**
+ * @var TPagedDataSource paged data source object
+ */
+ private $_pagedDataSource=null;
+ private $_topPager=null;
+ private $_bottomPager=null;
+ /**
+ * @var ITemplate template used when empty data is bounded
+ */
+ private $_emptyTemplate=null;
+ /**
+ * @var boolean whether empty template is effective
+ */
+ private $_useEmptyTemplate=false;
+
+ /**
+ * @return string tag name (table) of the datagrid
+ */
+ protected function getTagName()
+ {
+ return 'table';
+ }
+
+ /**
+ * @return string Name of the class used in AutoGenerateColumns mode
+ */
+ protected function getAutoGenerateColumnName()
+ {
+ return 'TBoundColumn';
+ }
+
+ /**
+ * Adds objects parsed in template to datagrid.
+ * Datagrid columns are added into {@link getColumns Columns} collection.
+ * @param mixed object parsed in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TDataGridColumn)
+ $this->getColumns()->add($object);
+ else
+ parent::addParsedObject($object); // this is needed by EmptyTemplate
+ }
+
+ /**
+ * @return TDataGridColumnCollection manually specified datagrid columns
+ */
+ public function getColumns()
+ {
+ if(!$this->_columns)
+ $this->_columns=new TDataGridColumnCollection($this);
+ return $this->_columns;
+ }
+
+ /**
+ * @return TDataGridColumnCollection automatically generated datagrid columns
+ */
+ public function getAutoColumns()
+ {
+ if(!$this->_autoColumns)
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ return $this->_autoColumns;
+ }
+
+ /**
+ * @return TDataGridItemCollection datagrid item collection
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataGridItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by datagrid.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return string the URL of the background image for the datagrid
+ */
+ public function getBackImageUrl()
+ {
+ return $this->getStyle()->getBackImageUrl();
+ }
+
+ /**
+ * @param string the URL of the background image for the datagrid
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * @return TTableItemStyle the style for every item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TDataGridPagerStyle the style for pager
+ */
+ public function getPagerStyle()
+ {
+ if(($style=$this->getViewState('PagerStyle',null))===null)
+ {
+ $style=new TDataGridPagerStyle;
+ $this->setViewState('PagerStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for thead element, if any
+ * @since 3.1.1
+ */
+ public function getTableHeadStyle()
+ {
+ if(($style=$this->getViewState('TableHeadStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableHeadStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tbody element, if any
+ * @since 3.1.1
+ */
+ public function getTableBodyStyle()
+ {
+ if(($style=$this->getViewState('TableBodyStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableBodyStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tfoot element, if any
+ * @since 3.1.1
+ */
+ public function getTableFootStyle()
+ {
+ if(($style=$this->getViewState('TableFootStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableFootStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string caption for the datagrid
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string caption for the datagrid
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',$value,'');
+ }
+
+ /**
+ * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @param TTableCaptionAlign datagrid caption alignment. Valid values include
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @return TDataGridItem the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TDataGridItem the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
+ */
+ public function getTopPager()
+ {
+ return $this->_topPager;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
+ */
+ public function getBottomPager()
+ {
+ return $this->_bottomPager;
+ }
+
+ /**
+ * @return TDataGridItem the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TDataGridItem the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return boolean whether sorting is enabled. Defaults to false.
+ */
+ public function getAllowSorting()
+ {
+ return $this->getViewState('AllowSorting',false);
+ }
+
+ /**
+ * @param boolean whether sorting is enabled
+ */
+ public function setAllowSorting($value)
+ {
+ $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
+ */
+ public function getAutoGenerateColumns()
+ {
+ return $this->getViewState('AutoGenerateColumns',true);
+ }
+
+ /**
+ * @param boolean whether datagrid columns should be automatically generated
+ */
+ public function setAutoGenerateColumns($value)
+ {
+ $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the header should be displayed. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether the header should be displayed
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be displayed. Defaults to false.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',false);
+ }
+
+ /**
+ * @param boolean whether the footer should be displayed
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datagrid
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datagrid
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * {@link TDataGridItem} child controls.
+ * If the event parameter is {@link TDataGridCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataGridCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ $this->setSelectedItemIndex($param->getItem()->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_SORT)===0)
+ {
+ $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE)===0)
+ {
+ $p=$param->getCommandParameter();
+ if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
+ $pageIndex=$this->getCurrentPageIndex()-1;
+ else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
+ $pageIndex=0;
+ else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
+ $pageIndex=$this->getPageCount()-1;
+ else
+ $pageIndex=TPropertyValue::ensureInteger($p)-1;
+ $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises OnCancelCommand event.
+ * This method is invoked when a button control raises OnCommand event
+ * with cancel command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnDeleteCommand event.
+ * This method is invoked when a button control raises OnCommand event
+ * with delete command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnEditCommand event.
+ * This method is invoked when a button control raises OnCommand event
+ * with edit command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnItemCommand event.
+ * This method is invoked when a button control raises OnCommand event.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnSortCommand event.
+ * This method is invoked when a button control raises OnCommand event
+ * with sort command name.
+ * @param TDataGridSortCommandEventParameter event parameter
+ */
+ public function onSortCommand($param)
+ {
+ $this->raiseEvent('OnSortCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnUpdateCommand event.
+ * This method is invoked when a button control raises OnCommand event
+ * with update command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnItemCreated event.
+ * This method is invoked right after a datagrid item is created and before
+ * added to page hierarchy.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises OnPagerCreated event.
+ * This method is invoked right after a datagrid pager is created and before
+ * added to page hierarchy.
+ * @param TDataGridPagerEventParameter event parameter
+ */
+ public function onPagerCreated($param)
+ {
+ $this->raiseEvent('OnPagerCreated',$this,$param);
+ }
+
+ /**
+ * Raises OnItemDataBound event.
+ * This method is invoked for each datagrid item after it performs
+ * databinding.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises OnPageIndexChanged event.
+ * This method is invoked when current page is changed.
+ * @param TDataGridPageChangedEventParameter event parameter
+ */
+ public function onPageIndexChanged($param)
+ {
+ $this->raiseEvent('OnPageIndexChanged',$this,$param);
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ if($this->_autoColumns)
+ {
+ $state=array();
+ foreach($this->_autoColumns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('AutoColumns',$state,array());
+ }
+ else
+ $this->clearViewState('AutoColumns');
+ if($this->_columns)
+ {
+ $state=array();
+ foreach($this->_columns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('Columns',$state,array());
+ }
+ else
+ $this->clearViewState('Columns');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if(!$this->getIsDataBound())
+ {
+ $state=$this->getViewState('AutoColumns',array());
+ if(!empty($state))
+ {
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ foreach($state as $st)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ $column->loadState($st);
+ $this->_autoColumns->add($column);
+ }
+ }
+ else
+ $this->_autoColumns=null;
+ $state=$this->getViewState('Columns',array());
+ if($this->_columns && $this->_columns->getCount()===count($state))
+ {
+ $i=0;
+ foreach($this->_columns as $column)
+ {
+ $column->loadState($state[$i]);
+ $i++;
+ }
+ }
+ $this->restoreGridFromViewState();
+ }
+ }
+
+ /**
+ * Clears up all items in the datagrid.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ $this->_topPager=null;
+ $this->_bottomPager=null;
+ $this->_useEmptyTemplate=false;
+ }
+
+ /**
+ * Restores datagrid content from viewstate.
+ */
+ protected function restoreGridFromViewState()
+ {
+ $this->reset();
+
+ $allowPaging=$this->getAllowPaging();
+
+ $itemCount=$this->getViewState('ItemCount',0);
+ $dsIndex=$this->getViewState('DataSourceIndex',0);
+
+ $columns=new TList($this->getColumns());
+ $columns->mergeWith($this->_autoColumns);
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ for($index=0;$index<$itemCount;++$index)
+ {
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Performs databinding to populate datagrid items from data source.
+ * This method is invoked by {@link dataBind()}.
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the bound data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
+ // get all columns
+ if($this->getAutoGenerateColumns())
+ {
+ $columns=new TList($this->getColumns());
+ $autoColumns=$this->createAutoColumns($data);
+ $columns->mergeWith($autoColumns);
+ }
+ else
+ $columns=$this->getColumns();
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ $index=0;
+ $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
+ $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
+ $this->setViewState('DataSourceIndex',$dsIndex,0);
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$row)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($row,$keyField));
+ else
+ $keys->add($key);
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
+ $index++;
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ $this->setViewState('ItemCount',$index,0);
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ $this->dataBindChildren();
+ }
+ }
+
+ /**
+ * Merges consecutive cells who have the same text.
+ * @since 3.1.1
+ */
+ private function groupCells()
+ {
+ if(($columns=$this->_allColumns)===null)
+ return;
+ $items=$this->getItems();
+ foreach($columns as $id=>$column)
+ {
+ if(!$column->getEnableCellGrouping())
+ continue;
+ $prevCell=null;
+ $prevCellText=null;
+ foreach($items as $item)
+ {
+ $itemType=$item->getItemType();
+ $cell=$item->getCells()->itemAt($id);
+ if(!$cell->getVisible())
+ continue;
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ if(($cellText=$this->getCellText($cell))==='')
+ {
+ $prevCell=null;
+ $prevCellText=null;
+ continue;
+ }
+ if($prevCell===null || $prevCellText!==$cellText)
+ {
+ $prevCell=$cell;
+ $prevCellText=$cellText;
+ }
+ else
+ {
+ if(($rowSpan=$prevCell->getRowSpan())===0)
+ $rowSpan=1;
+ $prevCell->setRowSpan($rowSpan+1);
+ $cell->setVisible(false);
+ }
+ }
+ }
+ }
+ }
+
+ private function getCellText($cell)
+ {
+ if(($data=$cell->getText())==='' && $cell->getHasControls())
+ {
+ $controls=$cell->getControls();
+ foreach($controls as $control)
+ {
+ if($control instanceof IDataRenderer)
+ return $control->getData();
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Creates a datagrid item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TDataGridItem created data list item
+ */
+ protected function createItem($itemIndex,$dataSourceIndex,$itemType)
+ {
+ return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
+ }
+
+ private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
+ {
+ $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
+ $this->initializeItem($item,$columns);
+ $param=new TDataGridItemEventParameter($item);
+ if($dataBind)
+ {
+ $item->setDataItem($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ }
+ else
+ {
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ }
+ return $item;
+ }
+
+ /**
+ * Initializes a datagrid item and cells inside it
+ * @param TDataGrid datagrid item to be initialized
+ * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
+ */
+ protected function initializeItem($item,$columns)
+ {
+ $cells=$item->getCells();
+ $itemType=$item->getItemType();
+ $index=0;
+ foreach($columns as $column)
+ {
+ if($itemType===TListItemType::Header)
+ $cell=new TTableHeaderCell;
+ else
+ $cell=new TTableCell;
+ if(($id=$column->getID())!=='')
+ $item->registerObject($id,$cell);
+ $cells->add($cell);
+ $column->initializeCell($cell,$index,$itemType);
+ $index++;
+ }
+ }
+
+ protected function createPager()
+ {
+ $pager=new TDataGridPager($this);
+ $this->buildPager($pager);
+ $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
+ $this->getControls()->add($pager);
+ return $pager;
+ }
+
+ /**
+ * Builds the pager content based on pager style.
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildPager($pager)
+ {
+ switch($this->getPagerStyle()->getMode())
+ {
+ case TDataGridPagerMode::NextPrev:
+ $this->buildNextPrevPager($pager);
+ break;
+ case TDataGridPagerMode::Numeric:
+ $this->buildNumericPager($pager);
+ break;
+ }
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param mixed the container pager instance of TActiveDatagridPager
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TDataGridPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
+ }
+ else
+ {
+ $button=new TButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ return $button;
+ }
+
+ /**
+ * Builds a next-prev pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNextPrevPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $currentPageIndex=$this->getCurrentPageIndex();
+ if($currentPageIndex===0)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ $controls->add("\n");
+ }
+
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
+ $controls->add($label);
+ }
+ else
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
+ $controls->add($button);
+ }
+ $controls->add("\n");
+ if($currentPageIndex===$this->getPageCount()-1)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
+ $controls->add($label);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ }
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a numeric pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNumericPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $maxButtonCount=$style->getPageButtonCount();
+ $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
+ $startPageIndex=1;
+ $endPageIndex=$buttonCount;
+ if($pageIndex>$endPageIndex)
+ {
+ $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
+ if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
+ $endPageIndex=$pageCount;
+ if($endPageIndex-$startPageIndex+1<$maxButtonCount)
+ {
+ if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
+ $startPageIndex=1;
+ }
+ }
+
+ if($startPageIndex>1)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ for($i=$startPageIndex;$i<=$endPageIndex;++$i)
+ {
+ if($i===$pageIndex)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
+ $controls->add($label);
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
+ $controls->add($button);
+ }
+ if($i<$endPageIndex)
+ $controls->add("\n");
+ }
+
+ if($pageCount>$endPageIndex)
+ {
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Automatically generates datagrid columns based on datasource schema
+ * @param Traversable data source bound to the datagrid
+ * @return TDataGridColumnCollection
+ */
+ protected function createAutoColumns($dataSource)
+ {
+ if(!$dataSource)
+ return null;
+ $autoColumns=$this->getAutoColumns();
+ $autoColumns->clear();
+ foreach($dataSource as $row)
+ {
+ foreach($row as $key=>$value)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ if(is_string($key))
+ {
+ $column->setHeaderText($key);
+ $column->setDataField($key);
+ $column->setSortExpression($key);
+ $autoColumns->add($column);
+ }
+ else
+ {
+ $column->setHeaderText(TListItemType::Item);
+ $column->setDataField($key);
+ $column->setSortExpression(TListItemType::Item);
+ $autoColumns->add($column);
+ }
+ }
+ break;
+ }
+ return $autoColumns;
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ $headerStyle=$this->getViewState('HeaderStyle',null);
+ $footerStyle=$this->getViewState('FooterStyle',null);
+ $pagerStyle=$this->getViewState('PagerStyle',null);
+ $separatorStyle=$this->getViewState('SeparatorStyle',null);
+
+ foreach($this->getControls() as $index=>$item)
+ {
+ if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
+ continue;
+ $itemType=$item->getItemType();
+ switch($itemType)
+ {
+ case TListItemType::Header:
+ if($headerStyle)
+ $item->getStyle()->mergeWith($headerStyle);
+ if(!$this->getShowHeader())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Footer:
+ if($footerStyle)
+ $item->getStyle()->mergeWith($footerStyle);
+ if(!$this->getShowFooter())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Separator:
+ if($separatorStyle)
+ $item->getStyle()->mergeWith($separatorStyle);
+ break;
+ case TListItemType::Item:
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ break;
+ case TListItemType::AlternatingItem:
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ break;
+ case TListItemType::SelectedItem:
+ if($selectedItemStyle)
+ $item->getStyle()->mergeWith($selectedItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::EditItem:
+ if($editItemStyle)
+ $item->getStyle()->mergeWith($editItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::Pager:
+ if($pagerStyle)
+ {
+ $item->getStyle()->mergeWith($pagerStyle);
+ if($index===0)
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ else
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if($this->_columns && $itemType!==TListItemType::Pager)
+ {
+ $n=$this->_columns->getCount();
+ $cells=$item->getCells();
+ for($i=0;$i<$n;++$i)
+ {
+ $cell=$cells->itemAt($i);
+ $column=$this->_columns->itemAt($i);
+ if(!$column->getVisible())
+ $cell->setVisible(false);
+ else
+ {
+ if($itemType===TListItemType::Header)
+ $style=$column->getHeaderStyle(false);
+ else if($itemType===TListItemType::Footer)
+ $style=$column->getFooterStyle(false);
+ else
+ $style=$column->getItemStyle(false);
+ if($style!==null)
+ $cell->getStyle()->mergeWith($style);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the openning tag for the datagrid control which will render table caption if present.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($caption=$this->getCaption())!=='')
+ {
+ if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
+ $writer->addAttribute('align',strtolower($align));
+ $writer->renderBeginTag('caption');
+ $writer->write($caption);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the datagrid.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ $this->groupCells();
+ if($this->_useEmptyTemplate)
+ {
+ $control=new TWebControl;
+ $control->setID($this->getClientID());
+ $control->copyBaseAttributes($this);
+ if($this->getHasStyle())
+ $control->getStyle()->copyFrom($this->getStyle());
+ $control->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $control->renderEndTag($writer);
+ }
+ else if($this->getViewState('ItemCount',0)>0)
+ {
+ $this->applyItemStyles();
+ if($this->_topPager)
+ {
+ $this->_topPager->renderControl($writer);
+ $writer->writeLine();
+ }
+ $this->renderTable($writer);
+ if($this->_bottomPager)
+ {
+ $writer->writeLine();
+ $this->_bottomPager->renderControl($writer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the tabular data.
+ * @param THtmlWriter writer
+ */
+ protected function renderTable($writer)
+ {
+ $this->renderBeginTag($writer);
+ if($this->_header && $this->_header->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableHeadStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('thead');
+ $this->_header->render($writer);
+ $writer->renderEndTag();
+ }
+ $writer->writeLine();
+ if($style=$this->getViewState('TableBodyStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tbody');
+ foreach($this->getItems() as $item)
+ $item->renderControl($writer);
+ $writer->renderEndTag();
+
+ if($this->_footer && $this->_footer->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableFootStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tfoot');
+ $this->_footer->render($writer);
+ $writer->renderEndTag();
+ }
+
+ $writer->writeLine();
+ $this->renderEndTag($writer);
+ }
+}
+
+/**
+ * TDataGridItemEventParameter class
+ *
+ * TDataGridItemEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridItem control responsible for the event.
+ * @var TDataGridItem
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item related with the corresponding event
+ */
+ public function __construct(TDataGridItem $item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TDataGridItem datagrid item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataGridPagerEventParameter class
+ *
+ * TDataGridPagerEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
+ * The {@link getPager Pager} property indicates the datagrid pager related with the event.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridPager control responsible for the event.
+ * @var TDataGridPager
+ */
+ protected $_pager=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function __construct(TDataGridPager $pager)
+ {
+ $this->_pager=$pager;
+ }
+
+ /**
+ * @return TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function getPager()
+ {
+ return $this->_pager;
+ }
+}
+
+/**
+ * TDataGridCommandEventParameter class
+ *
+ * TDataGridCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the Command event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the Command event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataGridSortCommandEventParameter class
+ *
+ * TDataGridSortCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
+ * gives the sort expression carried with the sort command.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridSortCommandEventParameter extends TEventParameter
+{
+ /**
+ * @var string sort expression
+ */
+ private $_sortExpression='';
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the OnCommand event.
+ * @param TDataGridCommandEventParameter command event parameter
+ */
+ public function __construct($source,TDataGridCommandEventParameter $param)
+ {
+ $this->_source=$source;
+ $this->_sortExpression=$param->getCommandParameter();
+ }
+
+ /**
+ * @return TControl the control originally raises the OnCommand event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return string sort expression
+ */
+ public function getSortExpression()
+ {
+ return $this->_sortExpression;
+ }
+}
+
+/**
+ * TDataGridPageChangedEventParameter class
+ *
+ * TDataGridPageChangedEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
+ * returns the new page index carried with the page command.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPageChangedEventParameter extends TEventParameter
+{
+ /**
+ * @var integer new page index
+ */
+ private $_newIndex;
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the OnCommand event.
+ * @param integer new page index
+ */
+ public function __construct($source,$newPageIndex)
+ {
+ $this->_source=$source;
+ $this->_newIndex=$newPageIndex;
+ }
+
+ /**
+ * @return TControl the control originally raises the OnCommand event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return integer new page index
+ */
+ public function getNewPageIndex()
+ {
+ return $this->_newIndex;
+ }
+}
+
+/**
+ * TDataGridItem class
+ *
+ * A TDataGridItem control represents an item in the {@link TDataGrid} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
+ * gives the index of the item from the bound data source.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItem extends TTableRow implements INamingContainer
+{
+ /**
+ * @var integer index of the data item in the Items collection of datagrid
+ */
+ private $_itemIndex='';
+ /**
+ * @var integer index of the item from the bound data source
+ */
+ private $_dataSourceIndex=0;
+ /**
+ * type of the TDataGridItem
+ * @var string
+ */
+ private $_itemType='';
+ /**
+ * value of the data item
+ * @var mixed
+ */
+ private $_data=null;
+
+ /**
+ * Constructor.
+ * @param integer zero-based index of the item in the item collection of datagrid
+ * @param TListItemType item type
+ */
+ public function __construct($itemIndex,$dataSourceIndex,$itemType)
+ {
+ $this->_itemIndex=$itemIndex;
+ $this->_dataSourceIndex=$dataSourceIndex;
+ $this->setItemType($itemType);
+ if($itemType===TListItemType::Header)
+ $this->setTableSection(TTableRowSection::Header);
+ else if($itemType===TListItemType::Footer)
+ $this->setTableSection(TTableRowSection::Footer);
+ }
+
+ /**
+ * @return TListItemType item type.
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datagrid
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * @return integer the index of the datagrid item from the bound data source
+ */
+ public function getDataSourceIndex()
+ {
+ return $this->_dataSourceIndex;
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for OnCommand event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+
+/**
+ * TDataGridPager class.
+ *
+ * TDataGridPager represents a datagrid pager.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPager extends TPanel implements INamingContainer
+{
+ private $_dataGrid;
+
+ /**
+ * Constructor.
+ * @param TDataGrid datagrid object
+ */
+ public function __construct($dataGrid)
+ {
+ $this->_dataGrid=$dataGrid;
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for OnCommand event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @return TDataGrid the datagrid owning this pager
+ */
+ public function getDataGrid()
+ {
+ return $this->_dataGrid;
+ }
+
+ /**
+ * @return string item type.
+ */
+ public function getItemType()
+ {
+ return TListItemType::Pager;
+ }
+}
+
+
+/**
+ * TDataGridItemCollection class.
+ *
+ * TDataGridItemCollection represents a collection of data grid items.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridItem.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridItem)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
+ }
+}
+
+/**
+ * TDataGridColumnCollection class.
+ *
+ * TDataGridColumnCollection represents a collection of data grid columns.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridColumnCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TDataGrid the control that owns this collection.
+ */
+ public function __construct(TDataGrid $owner)
+ {
+ $this->_o=$owner;
+ }
+
+ /**
+ * @return TDataGrid the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridColumn.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridColumn)
+ {
+ $item->setOwner($this->_o);
+ parent::insertAt($index,$item);
+ }
+ else
+ throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
+ }
+}
+
+/**
+ * TDataGridPagerMode class.
+ * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
+ *
+ * The following enumerable values are defined:
+ * - NextPrev: pager buttons are displayed as next and previous pages
+ * - Numeric: pager buttons are displayed as numeric page numbers
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerMode extends TEnumerable
+{
+ const NextPrev='NextPrev';
+ const Numeric='Numeric';
+}
+
+
+/**
+ * TDataGridPagerButtonType class.
+ * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form submit buttons
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerButtonType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+}
+
+
+/**
+ * TDataGridPagerPosition class.
+ * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
+ *
+ * The following enumerable values are defined:
+ * - Bottom: pager appears only at the bottom of the data grid.
+ * - Top: pager appears only at the top of the data grid.
+ * - TopAndBottom: pager appears on both top and bottom of the data grid.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerPosition extends TEnumerable
+{
+ const Bottom='Bottom';
+ const Top='Top';
+ const TopAndBottom='TopAndBottom';
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php
index d37fbc40..4794fbf8 100644
--- a/framework/Web/UI/WebControls/TDataGridColumn.php
+++ b/framework/Web/UI/WebControls/TDataGridColumn.php
@@ -1,567 +1,567 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Util.TDataFieldAccessor');
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridColumn class
- *
- * TDataGridColumn serves as the base class for the different column types of
- * the {@link TDataGrid} control.
- * TDataGridColumn defines the properties and methods that are common among
- * all datagrid column types. In particular, it initializes header and footer
- * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
- * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
- * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
- * will be displayed instead in the header cell.
- * The {@link getItemStyle ItemStyle} is applied to cells that belong to
- * non-header and -footer datagrid items.
- *
- * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
- * is not empty, the header cell will display a button (linkbutton or imagebutton)
- * that will bubble the sort command event to the datagrid.
- *
- * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
- * and {@link setFooterRenderer FooterRenderer} which can be used to specify
- * the layout of header and footer column cells.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
- * If a column has this property set true, consecutive cells having the same content in this
- * column will be grouped into one cell.
- * Note, there are some limitations to cell grouping. We determine the cell content according to
- * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
- * some child controls, we will pick up the first control who implements {@link IDataRenderer}
- * and obtain its {@link IDataRenderer::getData Data} property.
- *
- * The following datagrid column types are provided by the framework currently,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * To create your own column class, simply override {@link initializeCell()} method,
- * which is the major logic for managing the data and presentation of cells in the column.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataGridColumn extends TApplicationComponent
-{
- private $_id='';
- private $_owner=null;
- private $_viewState=array();
-
- /**
- * @return string the ID of the column.
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * Sets the ID of the column.
- * By explicitly specifying the column ID, one can access the column
- * by $templateControl->ColumnID.
- * @param string the ID of the column.
- * @throws TInvalidDataValueException if the ID is of bad format
- */
- public function setID($value)
- {
- if(!preg_match(TControl::ID_FORMAT,$value))
- throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
- $this->_id=$value;
- }
-
- /**
- * @return string the text to be displayed in the header of this column
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * @param string text to be displayed in the header of this column
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',$value,'');
- }
-
- /**
- * @return string the url of the image to be displayed in header
- */
- public function getHeaderImageUrl()
- {
- return $this->getViewState('HeaderImageUrl','');
- }
-
- /**
- * @param string the url of the image to be displayed in header
- */
- public function setHeaderImageUrl($value)
- {
- $this->setViewState('HeaderImageUrl',$value,'');
- }
-
- /**
- * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the column header cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column header cell.
- * If the class implements {@link IDataRenderer}, the Data property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle($createStyle=true)
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the text to be displayed in the footer of this column
- */
- public function getFooterText()
- {
- return $this->getViewState('FooterText','');
- }
-
- /**
- * @param string text to be displayed in the footer of this column
- */
- public function setFooterText($value)
- {
- $this->setViewState('FooterText',$value,'');
- }
-
- /**
- * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the column footer cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column footer cell.
- * If the class implements {@link IDataRenderer}, the Data property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle($createStyle=true)
- {
- if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle($createStyle=true)
- {
- if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the name of the field or expression for sorting
- */
- public function getSortExpression()
- {
- return $this->getViewState('SortExpression','');
- }
-
- /**
- * @param string the name of the field or expression for sorting
- */
- public function setSortExpression($value)
- {
- $this->setViewState('SortExpression',$value,'');
- }
-
- /**
- * @return boolean whether cells having the same content should be grouped together. Defaults to false.
- * @since 3.1.1
- */
- public function getEnableCellGrouping()
- {
- return $this->getViewState('EnableCellGrouping',false);
- }
-
- /**
- * @param boolean whether cells having the same content should be grouped together.
- * @since 3.1.1
- */
- public function setEnableCellGrouping($value)
- {
- $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the column is visible. Defaults to true.
- */
- public function getVisible($checkParents=true)
- {
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the column is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a viewstate value.
- *
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- protected function getViewState($key,$defaultValue=null)
- {
- return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- protected function setViewState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_viewState[$key]);
- else
- $this->_viewState[$key]=$value;
- }
-
- /**
- * Loads persistent state values.
- * @param mixed state values
- */
- public function loadState($state)
- {
- $this->_viewState=$state;
- }
-
- /**
- * Saves persistent state values.
- * @return mixed values to be saved
- */
- public function saveState()
- {
- return $this->_viewState;
- }
-
- /**
- * @return TDataGrid datagrid that owns this column
- */
- public function getOwner()
- {
- return $this->_owner;
- }
-
- /**
- * @param TDataGrid datagrid object that owns this column
- */
- public function setOwner(TDataGrid $value)
- {
- $this->_owner=$value;
- }
-
- /**
- * Initializes the column.
- * This method is invoked by {@link TDataGrid} when the column
- * is about to be used to initialize datagrid items.
- * Derived classes may override this method to do additional initialization.
- */
- public function initialize()
- {
- }
-
- /**
- * Fetches the value of the data at the specified field.
- * If the data is an array, the field is used as an array key.
- * If the data is an of {@link TMap}, {@link TList} or their derived class,
- * the field is used as a key value.
- * If the data is a component, the field is used as the name of a property.
- * @param mixed data containing the field of value
- * @param string the data field
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data or the field is invalid.
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-
-
- /**
- * Initializes the specified cell to its initial values.
- * The default implementation sets the content of header and footer cells.
- * If sorting is enabled by the grid and sort expression is specified in the column,
- * the header cell will show a link/image button. Otherwise, the header/footer cell
- * will only show static text/image.
- * This method can be overriden to provide customized intialization to column cells.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Header)
- $this->initializeHeaderCell($cell,$columnIndex);
- else if($itemType===TListItemType::Footer)
- $this->initializeFooterCell($cell,$columnIndex);
- }
-
- /**
- * Returns a value indicating whether this column allows sorting.
- * The column allows sorting only when {@link getSortExpression SortExpression}
- * is not empty and the datagrid allows sorting.
- * @return boolean whether this column allows sorting
- */
- public function getAllowSorting()
- {
- return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
- }
-
- /**
- * Initializes the header cell.
- *
- * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
- * instantiate the header cell. If that is not available, it will populate
- * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
- * and {@link getHeaderText HeaderText} property values.
- *
- * If the column allows sorting, image or text will be created as
- * a button which issues Sort command upon user click.
- *
- * @param TTableCell the cell to be initialized
- * @param integer the index to the Columns property that the cell resides in.
- */
- protected function initializeHeaderCell($cell,$columnIndex)
- {
- $text=$this->getHeaderText();
-
- if(($classPath=$this->getHeaderRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IDataRenderer)
- {
- if($control instanceof IItemDataRenderer)
- {
- $item=$cell->getParent();
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $control->setData($text);
- }
- }
- else if($this->getAllowSorting())
- {
- $sortExpression=$this->getSortExpression();
- if(($url=$this->getHeaderImageUrl())!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- $button->setImageUrl($url);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- if($text!=='')
- $button->setAlternateText($text);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else if($text!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- $button->setText($text);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else
- $cell->setText(' ');
- }
- else
- {
- if(($url=$this->getHeaderImageUrl())!=='')
- {
- $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
- $image->setImageUrl($url);
- if($text!=='')
- $image->setAlternateText($text);
- $cell->getControls()->add($image);
- }
- else if($text!=='')
- $cell->setText($text);
- else
- $cell->setText(' ');
- }
- }
-
- /**
- * Initializes the footer cell.
- *
- * This method attempts to use {@link getFooterRenderer FooterRenderer} to
- * instantiate the footer cell. If that is not available, it will populate
- * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl}
- *
- * @param TTableCell the cell to be initialized
- * @param integer the index to the Columns property that the cell resides in.
- */
- protected function initializeFooterCell($cell,$columnIndex)
- {
- $text=$this->getFooterText();
- if(($classPath=$this->getFooterRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IDataRenderer)
- {
- if($control instanceof IItemDataRenderer)
- {
- $item=$cell->getParent();
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $control->setData($text);
- }
- }
- else if($text!=='')
- $cell->setText($text);
- else
- $cell->setText(' ');
- }
-
- /**
- * Formats the text value according to a format string.
- * If the format string is empty, the original value is converted into
- * a string and returned.
- * If the format string starts with '#', the string is treated as a PHP expression
- * within which the token '{0}' is translated with the data value to be formated.
- * Otherwise, the format string and the data value are passed
- * as the first and second parameters in {@link sprintf}.
- * @param string format string
- * @param mixed the data to be formatted
- * @return string the formatted result
- */
- protected function formatDataValue($formatString,$value)
- {
- if($formatString==='')
- return TPropertyValue::ensureString($value);
- else if($formatString[0]==='#')
- {
- $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
- try
- {
- if(eval("\$result=$expression;")===false)
- throw new Exception('');
- return $result;
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
- }
- }
- else
- return sprintf($formatString,$value);
- }
-}
-
-
-/**
- * TButtonColumnType class.
- * TButtonColumnType defines the enumerable type for the possible types of buttons
- * that can be used in a {@link TButtonColumn}.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form buttons
- * - ImageButton: image buttons
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TButtonColumnType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
- const ImageButton='ImageButton';
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Util.TDataFieldAccessor');
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridColumn class
+ *
+ * TDataGridColumn serves as the base class for the different column types of
+ * the {@link TDataGrid} control.
+ * TDataGridColumn defines the properties and methods that are common among
+ * all datagrid column types. In particular, it initializes header and footer
+ * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
+ * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
+ * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
+ * will be displayed instead in the header cell.
+ * The {@link getItemStyle ItemStyle} is applied to cells that belong to
+ * non-header and -footer datagrid items.
+ *
+ * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
+ * is not empty, the header cell will display a button (linkbutton or imagebutton)
+ * that will bubble the sort command event to the datagrid.
+ *
+ * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
+ * and {@link setFooterRenderer FooterRenderer} which can be used to specify
+ * the layout of header and footer column cells.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
+ * If a column has this property set true, consecutive cells having the same content in this
+ * column will be grouped into one cell.
+ * Note, there are some limitations to cell grouping. We determine the cell content according to
+ * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
+ * some child controls, we will pick up the first control who implements {@link IDataRenderer}
+ * and obtain its {@link IDataRenderer::getData Data} property.
+ *
+ * The following datagrid column types are provided by the framework currently,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * To create your own column class, simply override {@link initializeCell()} method,
+ * which is the major logic for managing the data and presentation of cells in the column.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataGridColumn extends TApplicationComponent
+{
+ private $_id='';
+ private $_owner=null;
+ private $_viewState=array();
+
+ /**
+ * @return string the ID of the column.
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Sets the ID of the column.
+ * By explicitly specifying the column ID, one can access the column
+ * by $templateControl->ColumnID.
+ * @param string the ID of the column.
+ * @throws TInvalidDataValueException if the ID is of bad format
+ */
+ public function setID($value)
+ {
+ if(!preg_match(TControl::ID_FORMAT,$value))
+ throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string the text to be displayed in the header of this column
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * @param string text to be displayed in the header of this column
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',$value,'');
+ }
+
+ /**
+ * @return string the url of the image to be displayed in header
+ */
+ public function getHeaderImageUrl()
+ {
+ return $this->getViewState('HeaderImageUrl','');
+ }
+
+ /**
+ * @param string the url of the image to be displayed in header
+ */
+ public function setHeaderImageUrl($value)
+ {
+ $this->setViewState('HeaderImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the column header cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column header cell.
+ * If the class implements {@link IDataRenderer}, the Data property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the text to be displayed in the footer of this column
+ */
+ public function getFooterText()
+ {
+ return $this->getViewState('FooterText','');
+ }
+
+ /**
+ * @param string text to be displayed in the footer of this column
+ */
+ public function setFooterText($value)
+ {
+ $this->setViewState('FooterText',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the column footer cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column footer cell.
+ * If the class implements {@link IDataRenderer}, the Data property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the name of the field or expression for sorting
+ */
+ public function getSortExpression()
+ {
+ return $this->getViewState('SortExpression','');
+ }
+
+ /**
+ * @param string the name of the field or expression for sorting
+ */
+ public function setSortExpression($value)
+ {
+ $this->setViewState('SortExpression',$value,'');
+ }
+
+ /**
+ * @return boolean whether cells having the same content should be grouped together. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getEnableCellGrouping()
+ {
+ return $this->getViewState('EnableCellGrouping',false);
+ }
+
+ /**
+ * @param boolean whether cells having the same content should be grouped together.
+ * @since 3.1.1
+ */
+ public function setEnableCellGrouping($value)
+ {
+ $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the column is visible. Defaults to true.
+ */
+ public function getVisible($checkParents=true)
+ {
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the column is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ protected function getViewState($key,$defaultValue=null)
+ {
+ return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ protected function setViewState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_viewState[$key]);
+ else
+ $this->_viewState[$key]=$value;
+ }
+
+ /**
+ * Loads persistent state values.
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ $this->_viewState=$state;
+ }
+
+ /**
+ * Saves persistent state values.
+ * @return mixed values to be saved
+ */
+ public function saveState()
+ {
+ return $this->_viewState;
+ }
+
+ /**
+ * @return TDataGrid datagrid that owns this column
+ */
+ public function getOwner()
+ {
+ return $this->_owner;
+ }
+
+ /**
+ * @param TDataGrid datagrid object that owns this column
+ */
+ public function setOwner(TDataGrid $value)
+ {
+ $this->_owner=$value;
+ }
+
+ /**
+ * Initializes the column.
+ * This method is invoked by {@link TDataGrid} when the column
+ * is about to be used to initialize datagrid items.
+ * Derived classes may override this method to do additional initialization.
+ */
+ public function initialize()
+ {
+ }
+
+ /**
+ * Fetches the value of the data at the specified field.
+ * If the data is an array, the field is used as an array key.
+ * If the data is an of {@link TMap}, {@link TList} or their derived class,
+ * the field is used as a key value.
+ * If the data is a component, the field is used as the name of a property.
+ * @param mixed data containing the field of value
+ * @param string the data field
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data or the field is invalid.
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * The default implementation sets the content of header and footer cells.
+ * If sorting is enabled by the grid and sort expression is specified in the column,
+ * the header cell will show a link/image button. Otherwise, the header/footer cell
+ * will only show static text/image.
+ * This method can be overriden to provide customized intialization to column cells.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Header)
+ $this->initializeHeaderCell($cell,$columnIndex);
+ else if($itemType===TListItemType::Footer)
+ $this->initializeFooterCell($cell,$columnIndex);
+ }
+
+ /**
+ * Returns a value indicating whether this column allows sorting.
+ * The column allows sorting only when {@link getSortExpression SortExpression}
+ * is not empty and the datagrid allows sorting.
+ * @return boolean whether this column allows sorting
+ */
+ public function getAllowSorting()
+ {
+ return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
+ }
+
+ /**
+ * Initializes the header cell.
+ *
+ * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
+ * instantiate the header cell. If that is not available, it will populate
+ * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
+ * and {@link getHeaderText HeaderText} property values.
+ *
+ * If the column allows sorting, image or text will be created as
+ * a button which issues Sort command upon user click.
+ *
+ * @param TTableCell the cell to be initialized
+ * @param integer the index to the Columns property that the cell resides in.
+ */
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText(' ');
+ }
+ else
+ {
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
+ $image->setImageUrl($url);
+ if($text!=='')
+ $image->setAlternateText($text);
+ $cell->getControls()->add($image);
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText(' ');
+ }
+ }
+
+ /**
+ * Initializes the footer cell.
+ *
+ * This method attempts to use {@link getFooterRenderer FooterRenderer} to
+ * instantiate the footer cell. If that is not available, it will populate
+ * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl}
+ *
+ * @param TTableCell the cell to be initialized
+ * @param integer the index to the Columns property that the cell resides in.
+ */
+ protected function initializeFooterCell($cell,$columnIndex)
+ {
+ $text=$this->getFooterText();
+ if(($classPath=$this->getFooterRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ }
+ else if($text!=='')
+ $cell->setText($text);
+ else
+ $cell->setText(' ');
+ }
+
+ /**
+ * Formats the text value according to a format string.
+ * If the format string is empty, the original value is converted into
+ * a string and returned.
+ * If the format string starts with '#', the string is treated as a PHP expression
+ * within which the token '{0}' is translated with the data value to be formated.
+ * Otherwise, the format string and the data value are passed
+ * as the first and second parameters in {@link sprintf}.
+ * @param string format string
+ * @param mixed the data to be formatted
+ * @return string the formatted result
+ */
+ protected function formatDataValue($formatString,$value)
+ {
+ if($formatString==='')
+ return TPropertyValue::ensureString($value);
+ else if($formatString[0]==='#')
+ {
+ $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
+ try
+ {
+ if(eval("\$result=$expression;")===false)
+ throw new Exception('');
+ return $result;
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
+ }
+ }
+ else
+ return sprintf($formatString,$value);
+ }
+}
+
+
+/**
+ * TButtonColumnType class.
+ * TButtonColumnType defines the enumerable type for the possible types of buttons
+ * that can be used in a {@link TButtonColumn}.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form buttons
+ * - ImageButton: image buttons
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TButtonColumnType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+ const ImageButton='ImageButton';
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridItemRenderer.php b/framework/Web/UI/WebControls/TDataGridItemRenderer.php
index 0e30a062..dbbbec11 100644
--- a/framework/Web/UI/WebControls/TDataGridItemRenderer.php
+++ b/framework/Web/UI/WebControls/TDataGridItemRenderer.php
@@ -1,30 +1,30 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataGridItemRenderer class
- *
- * TDataGridItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataGrid}.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataGridItemRenderer extends TItemDataRenderer
-{
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataGridItemRenderer class
+ *
+ * TDataGridItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataGrid}.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataGridItemRenderer extends TItemDataRenderer
+{
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridPagerStyle.php b/framework/Web/UI/WebControls/TDataGridPagerStyle.php
index 12346c06..2464291a 100644
--- a/framework/Web/UI/WebControls/TDataGridPagerStyle.php
+++ b/framework/Web/UI/WebControls/TDataGridPagerStyle.php
@@ -1,255 +1,255 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridPagerStyle class.
- *
- * TDataGridPagerStyle specifies the styles available for a datagrid pager.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerStyle extends TPanelStyle
-{
- private $_mode=null;
- private $_nextText=null;
- private $_prevText=null;
- private $_firstText=null;
- private $_lastText=null;
- private $_buttonCount=null;
- private $_position=null;
- private $_visible=null;
- private $_buttonType=null;
-
- /**
- * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
- */
- public function getMode()
- {
- return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
- }
-
- /**
- * @param TDataGridPagerMode pager mode.
- */
- public function setMode($value)
- {
- $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
- }
-
- /**
- * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
- }
-
- /**
- * @param TDataGridPagerButtonType the type of command button
- */
- public function setButtonType($value)
- {
- $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
- }
-
- /**
- * @return string text for the next page button. Defaults to '>'.
- */
- public function getNextPageText()
- {
- return $this->_nextText===null?'>':$this->_nextText;
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setNextPageText($value)
- {
- $this->_nextText=$value;
- }
-
- /**
- * @return string text for the previous page button. Defaults to '<'.
- */
- public function getPrevPageText()
- {
- return $this->_prevText===null?'<':$this->_prevText;
- }
-
- /**
- * @param string text for the previous page button.
- */
- public function setPrevPageText($value)
- {
- $this->_prevText=$value;
- }
-
- /**
- * @return string text for the first page button. Defaults to '<<'.
- */
- public function getFirstPageText()
- {
- return $this->_firstText===null?'<<':$this->_firstText;
- }
-
- /**
- * @param string text for the first page button.
- */
- public function setFirstPageText($value)
- {
- $this->_firstText=$value;
- }
-
- /**
- * @return string text for the last page button. Defaults to '>>'.
- */
- public function getLastPageText()
- {
- return $this->_lastText===null?'>>':$this->_lastText;
- }
-
- /**
- * @param string text for the last page button.
- */
- public function setLastPageText($value)
- {
- $this->_lastText=$value;
- }
-
- /**
- * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
- */
- public function getPageButtonCount()
- {
- return $this->_buttonCount===null?10:$this->_buttonCount;
- }
-
- /**
- * @param integer maximum number of pager buttons to be displayed
- * @throws TInvalidDataValueException if the value is less than 1.
- */
- public function setPageButtonCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
- $this->_buttonCount=$value;
- }
-
- /**
- * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
- */
- public function getPosition()
- {
- return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
- }
-
- /**
- * @param TDataGridPagerPosition where the pager is to be displayed.
- */
- public function setPosition($value)
- {
- $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
- }
-
- /**
- * @return boolean whether the pager is visible. Defaults to true.
- */
- public function getVisible()
- {
- return $this->_visible===null?true:$this->_visible;
- }
-
- /**
- * @param boolean whether the pager is visible.
- */
- public function setVisible($value)
- {
- $this->_visible=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Resets the style to the original empty state.
- */
- public function reset()
- {
- parent::reset();
- $this->_visible=null;
- $this->_position=null;
- $this->_buttonCount=null;
- $this->_prevText=null;
- $this->_nextText=null;
- $this->_mode=null;
- $this->_buttonType=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($style->_visible!==null)
- $this->_visible=$style->_visible;
- if($style->_position!==null)
- $this->_position=$style->_position;
- if($style->_buttonCount!==null)
- $this->_buttonCount=$style->_buttonCount;
- if($style->_prevText!==null)
- $this->_prevText=$style->_prevText;
- if($style->_nextText!==null)
- $this->_nextText=$style->_nextText;
- if($style->_mode!==null)
- $this->_mode=$style->_mode;
- if($style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($this->_visible===null)
- $this->_visible=$style->_visible;
- if($this->_position===null)
- $this->_position=$style->_position;
- if($this->_buttonCount===null)
- $this->_buttonCount=$style->_buttonCount;
- if($this->_prevText===null)
- $this->_prevText=$style->_prevText;
- if($this->_nextText===null)
- $this->_nextText=$style->_nextText;
- if($this->_mode===null)
- $this->_mode=$style->_mode;
- if($this->_buttonType===null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridPagerStyle class.
+ *
+ * TDataGridPagerStyle specifies the styles available for a datagrid pager.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerStyle extends TPanelStyle
+{
+ private $_mode=null;
+ private $_nextText=null;
+ private $_prevText=null;
+ private $_firstText=null;
+ private $_lastText=null;
+ private $_buttonCount=null;
+ private $_position=null;
+ private $_visible=null;
+ private $_buttonType=null;
+
+ /**
+ * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
+ */
+ public function getMode()
+ {
+ return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
+ }
+
+ /**
+ * @param TDataGridPagerMode pager mode.
+ */
+ public function setMode($value)
+ {
+ $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
+ }
+
+ /**
+ * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
+ }
+
+ /**
+ * @param TDataGridPagerButtonType the type of command button
+ */
+ public function setButtonType($value)
+ {
+ $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
+ }
+
+ /**
+ * @return string text for the next page button. Defaults to '>'.
+ */
+ public function getNextPageText()
+ {
+ return $this->_nextText===null?'>':$this->_nextText;
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setNextPageText($value)
+ {
+ $this->_nextText=$value;
+ }
+
+ /**
+ * @return string text for the previous page button. Defaults to '<'.
+ */
+ public function getPrevPageText()
+ {
+ return $this->_prevText===null?'<':$this->_prevText;
+ }
+
+ /**
+ * @param string text for the previous page button.
+ */
+ public function setPrevPageText($value)
+ {
+ $this->_prevText=$value;
+ }
+
+ /**
+ * @return string text for the first page button. Defaults to '<<'.
+ */
+ public function getFirstPageText()
+ {
+ return $this->_firstText===null?'<<':$this->_firstText;
+ }
+
+ /**
+ * @param string text for the first page button.
+ */
+ public function setFirstPageText($value)
+ {
+ $this->_firstText=$value;
+ }
+
+ /**
+ * @return string text for the last page button. Defaults to '>>'.
+ */
+ public function getLastPageText()
+ {
+ return $this->_lastText===null?'>>':$this->_lastText;
+ }
+
+ /**
+ * @param string text for the last page button.
+ */
+ public function setLastPageText($value)
+ {
+ $this->_lastText=$value;
+ }
+
+ /**
+ * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
+ */
+ public function getPageButtonCount()
+ {
+ return $this->_buttonCount===null?10:$this->_buttonCount;
+ }
+
+ /**
+ * @param integer maximum number of pager buttons to be displayed
+ * @throws TInvalidDataValueException if the value is less than 1.
+ */
+ public function setPageButtonCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
+ $this->_buttonCount=$value;
+ }
+
+ /**
+ * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
+ */
+ public function getPosition()
+ {
+ return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
+ }
+
+ /**
+ * @param TDataGridPagerPosition where the pager is to be displayed.
+ */
+ public function setPosition($value)
+ {
+ $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
+ }
+
+ /**
+ * @return boolean whether the pager is visible. Defaults to true.
+ */
+ public function getVisible()
+ {
+ return $this->_visible===null?true:$this->_visible;
+ }
+
+ /**
+ * @param boolean whether the pager is visible.
+ */
+ public function setVisible($value)
+ {
+ $this->_visible=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Resets the style to the original empty state.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_visible=null;
+ $this->_position=null;
+ $this->_buttonCount=null;
+ $this->_prevText=null;
+ $this->_nextText=null;
+ $this->_mode=null;
+ $this->_buttonType=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($style->_visible!==null)
+ $this->_visible=$style->_visible;
+ if($style->_position!==null)
+ $this->_position=$style->_position;
+ if($style->_buttonCount!==null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($style->_prevText!==null)
+ $this->_prevText=$style->_prevText;
+ if($style->_nextText!==null)
+ $this->_nextText=$style->_nextText;
+ if($style->_mode!==null)
+ $this->_mode=$style->_mode;
+ if($style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($this->_visible===null)
+ $this->_visible=$style->_visible;
+ if($this->_position===null)
+ $this->_position=$style->_position;
+ if($this->_buttonCount===null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($this->_prevText===null)
+ $this->_prevText=$style->_prevText;
+ if($this->_nextText===null)
+ $this->_nextText=$style->_nextText;
+ if($this->_mode===null)
+ $this->_mode=$style->_mode;
+ if($this->_buttonType===null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataList.php b/framework/Web/UI/WebControls/TDataList.php
index 43980c0c..49e9c749 100644
--- a/framework/Web/UI/WebControls/TDataList.php
+++ b/framework/Web/UI/WebControls/TDataList.php
@@ -1,1766 +1,1766 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseDataList class
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-/**
- * Includes TRepeatInfo class
- */
-Prado::using('System.Web.UI.WebControls.TRepeatInfo');
-
-/**
- * TDataList class
- *
- * TDataList represents a data bound and updatable list control.
- *
- * Like {@link TRepeater}, TDataList displays its content repeatedly based on
- * the data fetched from {@link setDataSource DataSource}.
- * The repeated contents in TDataList are called items, which are controls and
- * can be accessed through {@link getItems Items}. When {@link dataBind()} is
- * invoked, TDataList creates an item for each row of data and binds the data
- * row to the item. Optionally, a TDataList can have a header, a footer and/or
- * separators between items.
- *
- * TDataList differs from {@link TRepeater} in that it supports tiling the items
- * in different manners and it maintains status of items to handle data update.
- *
- * The layout of the repeated contents are specified by inline templates.
- * TDataList items, header, footer, etc. are being instantiated with the corresponding
- * templates when data is being bound to the repeater.
- *
- * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
- * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
- * as an external template (in fact, it can also be non-templated controls).
- *
- * A renderer can be any control class.
- * - If the class implements {@link IDataRenderer}, the Data
- * property will be set as the data row during databinding. Many PRADO controls
- * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
- * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set
- * as the zero-based index of the item in the datalist item collection, and
- * the ItemType property as the item's type (such as TListItemType::Item).
- * {@link TDataListItemRenderer} may be used as the convenient base class which
- * already implements {@link IDataItemRenderer}.
- *
- * The following properties are used to specify different types of template and renderer
- * for a datalist:
- * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
- * for each repeated row of data
- * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
- * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
- * will be used instead.
- * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
- * for the datalist header.
- * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
- * for the datalist footer.
- * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
- * for content to be displayed between items.
- * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
- * used when data bound to the datalist is empty.
- * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
- * for the row being editted.
- * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
- * for the row being selected.
- *
- * If a content type is defined with both a template and a renderer, the latter takes precedence.
- *
- * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
- * - create item based on templates or renderers
- * - set the row of data to the item
- * - raise {@link onItemCreated OnItemCreated}:
- * - add the item as a child control
- * - call dataBind() of the item
- * - raise {@link onItemDataBound OnItemDataBound}:
- *
- * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
- * within some datalist item raises a OnCommand event. Therefore,
- * you can handle all sorts of OnCommand event in a central place by
- * writing an event handler for {@link onItemCommand OnItemCommand}.
- *
- * An additional event is raised if the OnCommand event has one of the following
- * command names:
- * - edit: user wants to edit an item. OnEditCommand event will be raised.
- * - update: user wants to save the change to an item. OnUpdateCommand event will be raised.
- * - select: user selects an item. OnSelectedIndexChanged event will be raised.
- * - delete: user deletes an item. OnDeleteCommand event will be raised.
- * - cancel: user cancels previously editting action. OnCancelCommand event will be raised.
- *
- * TDataList provides a few properties to support tiling the items.
- * The number of columns used to display the data items is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
- * which can take one of the following values:
- * - Table (default): items are organized using HTML table and cells.
- * When using this layout, one can set {@link setCellPadding CellPadding} and
- * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
- * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
- * to add a table caption with the specified alignment.
- * - Flow: items are organized using HTML spans and breaks.
- * - Raw: TDataList does not generate any HTML tags to do the tiling.
- *
- * Items in TDataList can be in one of the three status: normal browsing,
- * being editted and being selected. To change the status of a particular
- * item, set {@link setSelectedItemIndex SelectedItemIndex} or
- * {@link setEditItemIndex EditItemIndex}. The former will change
- * the indicated item to selected mode, which will cause the item to
- * use {@link setSelectedItemTemplate SelectedItemTemplate} or
- * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
- * The latter will change the indicated item to edit mode and to use corresponding
- * template or renderer.
- * Note, if an item is in edit mode, then selecting this item will have no effect.
- *
- * Different styles may be applied to items in different status. The style
- * application is performed in a hierarchical way: Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * - item's own style
- * - {@link getItemStyle ItemStyle}
- * - {@link getAlternatingItemStyle AlternatingItemStyle}
- * - {@link getSelectedItemStyle SelectedItemStyle}
- * - {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- *
- * When a page containing a datalist is post back, the datalist will restore automatically
- * all its contents, including items, header, footer and separators.
- * However, the data row associated with each item will not be recovered and become null.
- * To access the data, use one of the following ways:
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datalist item and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
- * Be aware though, if the size of your dataset is big, your page size will become big. Some
- * complex data may also have serializing problem if saved in viewstate.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
-{
- /**
- * Command name that TDataList understands. They are case-insensitive.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
-
- /**
- * @var TDataListItemCollection item list
- */
- private $_items=null;
- /**
- * @var Itemplate various item templates
- */
- private $_itemTemplate=null;
- private $_emptyTemplate=null;
- private $_alternatingItemTemplate=null;
- private $_selectedItemTemplate=null;
- private $_editItemTemplate=null;
- private $_headerTemplate=null;
- private $_footerTemplate=null;
- private $_separatorTemplate=null;
- /**
- * @var TControl header item
- */
- private $_header=null;
- /**
- * @var TControl footer item
- */
- private $_footer=null;
-
- /**
- * @return TDataListItemCollection item list
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataListItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * @return string the class name for datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist items.
- * This property takes precedence over {@link getItemTemplate ItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setItemTemplate
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getAlternatingItemRenderer()
- {
- return $this->getViewState('AlternatingItemRenderer','');
- }
-
- /**
- * Sets the alternative item renderer class.
- *
- * If not empty, the class will be used to instantiate as alternative datalist items.
- * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setAlternatingItemTemplate
- * @since 3.1.0
- */
- public function setAlternatingItemRenderer($value)
- {
- $this->setViewState('AlternatingItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being editted.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEditItemTemplate
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSelectedItemRenderer()
- {
- return $this->getViewState('SelectedItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being selected.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSelectedItemTemplate
- * @since 3.1.0
- */
- public function setSelectedItemRenderer($value)
- {
- $this->setViewState('SelectedItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSeparatorRenderer()
- {
- return $this->getViewState('SeparatorRenderer','');
- }
-
- /**
- * Sets the datalist item separator renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist item separators.
- * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSeparatorTemplate
- * @since 3.1.0
- */
- public function setSeparatorRenderer($value)
- {
- $this->setViewState('SeparatorRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist header item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the datalist header renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist header item.
- * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setHeaderTemplate
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the datalist footer renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist footer item.
- * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setFooterTemplate
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEmptyRenderer()
- {
- return $this->getViewState('EmptyRenderer','');
- }
-
- /**
- * Sets the datalist empty renderer class.
- *
- * The empty renderer is created as the child of the datalist
- * if data bound to the datalist is empty.
- * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEmptyTemplate
- * @since 3.1.0
- */
- public function setEmptyRenderer($value)
- {
- $this->setViewState('EmptyRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the template for item
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the template for item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the template for each alternating item
- */
- public function getAlternatingItemTemplate()
- {
- return $this->_alternatingItemTemplate;
- }
-
- /**
- * @param ITemplate the template for each alternating item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setAlternatingItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_alternatingItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the selected item template
- */
- public function getSelectedItemTemplate()
- {
- return $this->_selectedItemTemplate;
- }
-
- /**
- * @param ITemplate the selected item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSelectedItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_selectedItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the edit item template
- */
- public function getEditItemTemplate()
- {
- return $this->_editItemTemplate;
- }
-
- /**
- * @param ITemplate the edit item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEditItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_editItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datalist
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datalist
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
- }
-
- /**
- * @return ITemplate the separator template
- */
- public function getSeparatorTemplate()
- {
- return $this->_separatorTemplate;
- }
-
- /**
- * @param ITemplate the separator template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSeparatorTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_separatorTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for separator
- */
- public function getSeparatorStyle()
- {
- if(($style=$this->getViewState('SeparatorStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SeparatorStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TControl the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return mixed the key value of the currently selected item
- * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
- */
- public function getSelectedDataKey()
- {
- if($this->getDataKeyField()==='')
- throw new TInvalidOperationException('datalist_datakeyfield_required');
- $index=$this->getSelectedItemIndex();
- $dataKeys=$this->getDataKeys();
- if($index>=0 && $index<$dataKeys->getCount())
- return $dataKeys->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return TControl the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return boolean whether the header should be shown. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether to show header
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be shown. Defaults to true.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',true);
- }
-
- /**
- * @param boolean whether to show footer
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TRepeatInfo repeat information (primarily used by control developers)
- */
- protected function getRepeatInfo()
- {
- if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
- {
- $repeatInfo=new TRepeatInfo;
- $this->setViewState('RepeatInfo',$repeatInfo,null);
- }
- return $repeatInfo;
- }
-
- /**
- * @return string caption of the table layout
- */
- public function getCaption()
- {
- return $this->getRepeatInfo()->getCaption();
- }
-
- /**
- * @param string caption of the table layout
- */
- public function setCaption($value)
- {
- $this->getRepeatInfo()->setCaption($value);
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getRepeatInfo()->getCaptionAlign();
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout.
- */
- public function setCaptionAlign($value)
- {
- $this->getRepeatInfo()->setCaptionAlign($value);
- }
-
- /**
- * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->getRepeatInfo()->getRepeatColumns();
- }
-
- /**
- * @param integer the number of columns that the list should be displayed with.
- */
- public function setRepeatColumns($value)
- {
- $this->getRepeatInfo()->setRepeatColumns($value);
- }
-
- /**
- * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
- */
- public function getRepeatDirection()
- {
- return $this->getRepeatInfo()->getRepeatDirection();
- }
-
- /**
- * @param TRepeatDirection the direction of traversing the list
- */
- public function setRepeatDirection($value)
- {
- $this->getRepeatInfo()->setRepeatDirection($value);
- }
-
- /**
- * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
- */
- public function getRepeatLayout()
- {
- return $this->getRepeatInfo()->getRepeatLayout();
- }
-
- /**
- * @param TRepeatLayout how the list should be displayed, using table or using line breaks
- */
- public function setRepeatLayout($value)
- {
- $this->getRepeatInfo()->setRepeatLayout($value);
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * datalist items and their child controls.
- * If the event parameter is {@link TDataListCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataListCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- if(($item=$param->getItem()) instanceof IItemDataRenderer)
- $this->setSelectedItemIndex($item->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Raises OnItemCreated event.
- * This method is invoked after a data list item is created and instantiated with
- * template, but before added to the page hierarchy.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises OnItemDataBound event.
- * This method is invoked right after an item is data bound.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises OnItemCommand event.
- * This method is invoked when a child control of the data list
- * raises an OnCommand event.
- * @param TDataListCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises OnEditCommand event.
- * This method is invoked when a child control of the data list
- * raises an OnCommand event and the command name is 'edit' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises OnDeleteCommand event.
- * This method is invoked when a child control of the data list
- * raises an OnCommand event and the command name is 'delete' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises OnUpdateCommand event.
- * This method is invoked when a child control of the data list
- * raises an OnCommand event and the command name is 'update' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises OnCancelCommand event.
- * This method is invoked when a child control of the data list
- * raises an OnCommand event and the command name is 'cancel' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Returns a value indicating whether this control contains header item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has header
- */
- public function getHasHeader()
- {
- return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains footer item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has footer
- */
- public function getHasFooter()
- {
- return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains separator items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasSeparators()
- {
- return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- }
-
- /**
- * Returns a style used for rendering items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer index of the item being rendered
- * @return TStyle item style
- */
- public function generateItemStyle($itemType,$index)
- {
- if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
- {
- $style=$item->getStyle();
- $item->clearStyle();
- return $style;
- }
- else
- return null;
- }
-
- /**
- * Renders an item in the list.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param THtmlWriter writer for rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the item in the item list
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index)
- {
- $item=$this->getItem($itemType,$index);
- if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
- $item->setTagName('div');
- $item->renderControl($writer);
- }
-
- /**
- * @param TListItemType item type
- * @param integer item index
- * @return TControl data list item with the specified item type and index
- */
- private function getItem($itemType,$index)
- {
- switch($itemType)
- {
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- case TListItemType::EditItem:
- return $this->getItems()->itemAt($index);
- case TListItemType::Header:
- return $this->getControls()->itemAt(0);
- case TListItemType::Footer:
- return $this->getControls()->itemAt($this->getControls()->getCount()-1);
- case TListItemType::Separator:
- $i=$index+$index+1;
- if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
- $i++;
- return $this->getControls()->itemAt($i);
- }
- return null;
- }
-
- /**
- * Creates a datalist item.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @return TControl the created item, null if item is not created
- */
- private function createItemInternal($itemIndex,$itemType)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a datalist item and performs databinding.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @param mixed data to be associated with the item
- * @return TControl the created item, null if item is not created
- */
- private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- if($item instanceof IDataRenderer)
- $item->setData($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- return $item;
- }
- else
- return null;
- }
-
- private function getAlternatingItemDisplay()
- {
- if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return array($classPath,$this->_alternatingItemTemplate);
- }
-
- private function getSelectedItemDisplay($itemIndex)
- {
- if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
- {
- if($itemIndex%2===0)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return $this->getAlternatingItemDisplay();
- }
- else
- return array($classPath,$this->_selectedItemTemplate);
- }
-
- private function getEditItemDisplay($itemIndex)
- {
- if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
- return $this->getSelectedItemDisplay($itemIndex);
- else
- return array($classPath,$this->_editItemTemplate);
- }
-
- /**
- * Creates a datalist item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TControl created datalist item
- */
- protected function createItem($itemIndex,$itemType)
- {
- $template=null;
- $classPath=null;
- switch($itemType)
- {
- case TListItemType::Item :
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- break;
- case TListItemType::AlternatingItem :
- list($classPath,$template)=$this->getAlternatingItemDisplay();
- break;
- case TListItemType::SelectedItem:
- list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
- break;
- case TListItemType::EditItem:
- list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
- break;
- case TListItemType::Header :
- $classPath=$this->getHeaderRenderer();
- $template=$this->_headerTemplate;
- break;
- case TListItemType::Footer :
- $classPath=$this->getFooterRenderer();
- $template=$this->_footerTemplate;
- break;
- case TListItemType::Separator :
- $classPath=$this->getSeparatorRenderer();
- $template=$this->_separatorTemplate;
- break;
- default:
- throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
- }
- if($classPath!=='')
- {
- $item=Prado::createComponent($classPath);
- if($item instanceof IItemDataRenderer)
- {
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- }
- }
- else if($template!==null)
- {
- $item=new TDataListItem;
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- $template->instantiateIn($item);
- }
- else
- $item=null;
-
- return $item;
- }
-
- /**
- * Creates empty datalist content.
- */
- protected function createEmptyContent()
- {
- if(($classPath=$this->getEmptyRenderer())!=='')
- $this->getControls()->add(Prado::createComponent($classPath));
- else if($this->_emptyTemplate!==null)
- $this->_emptyTemplate->instantiateIn($this);
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- // apply header style if any
- if($this->_header!==null && $this->_header instanceof IStyleable)
- {
- if($headerStyle=$this->getViewState('HeaderStyle',null))
- $this->_header->getStyle()->mergeWith($headerStyle);
- }
-
- // apply footer style if any
- if($this->_footer!==null && $this->_footer instanceof IStyleable)
- {
- if($footerStyle=$this->getViewState('FooterStyle',null))
- $this->_footer->getStyle()->mergeWith($footerStyle);
- }
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
-
- // apply item styles if any
- foreach($this->getItems() as $index=>$item)
- {
- if($index===$editIndex)
- $style=$editItemStyle;
- else if($index===$selectedIndex)
- $style=$selectedItemStyle;
- else if($index%2===0)
- $style=$itemStyle;
- else
- $style=$alternatingItemStyle;
- if($style && $item instanceof IStyleable)
- $item->getStyle()->mergeWith($style);
- }
-
- // apply separator style if any
- if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
- {
- $controls=$this->getControls();
- $count=$controls->getCount();
- for($i=$this->_header?2:1;$i<$count;$i+=2)
- {
- if(($separator=$controls->itemAt($i)) instanceof IStyleable)
- $separator->getStyle()->mergeWith($separatorStyle);
- }
- }
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getIsDataBound())
- $this->restoreItemsFromViewState();
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Clears up all items in the data list.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- }
-
- /**
- * Creates data list items based on viewstate information.
- */
- protected function restoreItemsFromViewState()
- {
- $this->reset();
- if(($itemCount=$this->getViewState('ItemCount',0))>0)
- {
- $items=$this->getItems();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $this->_header=$this->createItemInternal(-1,TListItemType::Header);
- for($i=0;$i<$itemCount;++$i)
- {
- if($hasSeparator && $i>0)
- $this->createItemInternal($i-1,TListItemType::Separator);
- if($i===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($i===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemInternal($i,$itemType));
- }
- $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
- }
- else
- $this->createEmptyContent();
- $this->clearChildState();
- }
-
- /**
- * Performs databinding to populate data list items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
- $itemIndex=0;
- $items=$this->getItems();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$dataItem)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($dataItem,$keyField));
- else
- $keys->add($key);
- if($itemIndex===0)
- $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
- if($hasSeparator && $itemIndex>0)
- $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
- if($itemIndex===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($itemIndex===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
- $itemIndex++;
- }
- if($itemIndex>0)
- $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
- else
- {
- $this->createEmptyContent();
- $this->dataBindChildren();
- }
- $this->setViewState('ItemCount',$itemIndex,0);
- }
-
- /**
- * Renders the data list control.
- * This method overrides the parent implementation.
- * @param THtmlWriter writer for rendering purpose.
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- if($this->getItemCount()>0)
- {
- $this->applyItemStyles();
- $repeatInfo=$this->getRepeatInfo();
- $repeatInfo->renderRepeater($writer,$this);
- }
- else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
- parent::render($writer);
- }
- }
-}
-
-
-/**
- * TDataListItemEventParameter class
- *
- * TDataListItemEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
- * The {@link getItem Item} property indicates the DataList item related with the event.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemEventParameter extends TEventParameter
-{
- /**
- * The datalist item control responsible for the event.
- * @var TControl
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TControl DataList item related with the corresponding event
- */
- public function __construct($item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TControl datalist item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataListCommandEventParameter class
- *
- * TDataListCommandEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
- *
- * The {@link getItem Item} property indicates the DataList item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TControl the datalist item control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the OnCommand event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl datalist item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TControl the datalist item control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the OnCommand event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataListItem class
- *
- * A TDataListItem control represents an item in the {@link TDataList} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of DataList
- */
- private $_itemIndex;
- /**
- * type of the TDataListItem
- * @var TListItemType
- */
- private $_itemType;
- /**
- * value of the data associated with this item
- * @var mixed
- */
- private $_data;
-
- private $_tagName='span';
-
- /**
- * Returns the tag name used for this control.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return $this->_tagName;
- }
-
- /**
- * @param string tag name of the control to be rendered
- */
- public function setTagName($value)
- {
- $this->_tagName=$value;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by a datalist item.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datalist
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for OnCommand event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-/**
- * TDataListItemCollection class.
- *
- * TDataListItemCollection represents a collection of data list items.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TControl descendants.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseDataList class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+/**
+ * Includes TRepeatInfo class
+ */
+Prado::using('System.Web.UI.WebControls.TRepeatInfo');
+
+/**
+ * TDataList class
+ *
+ * TDataList represents a data bound and updatable list control.
+ *
+ * Like {@link TRepeater}, TDataList displays its content repeatedly based on
+ * the data fetched from {@link setDataSource DataSource}.
+ * The repeated contents in TDataList are called items, which are controls and
+ * can be accessed through {@link getItems Items}. When {@link dataBind()} is
+ * invoked, TDataList creates an item for each row of data and binds the data
+ * row to the item. Optionally, a TDataList can have a header, a footer and/or
+ * separators between items.
+ *
+ * TDataList differs from {@link TRepeater} in that it supports tiling the items
+ * in different manners and it maintains status of items to handle data update.
+ *
+ * The layout of the repeated contents are specified by inline templates.
+ * TDataList items, header, footer, etc. are being instantiated with the corresponding
+ * templates when data is being bound to the repeater.
+ *
+ * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
+ * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
+ * as an external template (in fact, it can also be non-templated controls).
+ *
+ * A renderer can be any control class.
+ * - If the class implements {@link IDataRenderer}, the Data
+ * property will be set as the data row during databinding. Many PRADO controls
+ * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
+ * - If the class implements {@link IItemDataRenderer}, the ItemIndex property will be set
+ * as the zero-based index of the item in the datalist item collection, and
+ * the ItemType property as the item's type (such as TListItemType::Item).
+ * {@link TDataListItemRenderer} may be used as the convenient base class which
+ * already implements {@link IDataItemRenderer}.
+ *
+ * The following properties are used to specify different types of template and renderer
+ * for a datalist:
+ * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
+ * for each repeated row of data
+ * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
+ * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
+ * will be used instead.
+ * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
+ * for the datalist header.
+ * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
+ * for the datalist footer.
+ * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
+ * for content to be displayed between items.
+ * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
+ * used when data bound to the datalist is empty.
+ * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
+ * for the row being editted.
+ * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
+ * for the row being selected.
+ *
+ * If a content type is defined with both a template and a renderer, the latter takes precedence.
+ *
+ * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
+ * - create item based on templates or renderers
+ * - set the row of data to the item
+ * - raise {@link onItemCreated OnItemCreated}:
+ * - add the item as a child control
+ * - call dataBind() of the item
+ * - raise {@link onItemDataBound OnItemDataBound}:
+ *
+ * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
+ * within some datalist item raises a OnCommand event. Therefore,
+ * you can handle all sorts of OnCommand event in a central place by
+ * writing an event handler for {@link onItemCommand OnItemCommand}.
+ *
+ * An additional event is raised if the OnCommand event has one of the following
+ * command names:
+ * - edit: user wants to edit an item. OnEditCommand event will be raised.
+ * - update: user wants to save the change to an item. OnUpdateCommand event will be raised.
+ * - select: user selects an item. OnSelectedIndexChanged event will be raised.
+ * - delete: user deletes an item. OnDeleteCommand event will be raised.
+ * - cancel: user cancels previously editting action. OnCancelCommand event will be raised.
+ *
+ * TDataList provides a few properties to support tiling the items.
+ * The number of columns used to display the data items is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
+ * which can take one of the following values:
+ * - Table (default): items are organized using HTML table and cells.
+ * When using this layout, one can set {@link setCellPadding CellPadding} and
+ * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
+ * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
+ * to add a table caption with the specified alignment.
+ * - Flow: items are organized using HTML spans and breaks.
+ * - Raw: TDataList does not generate any HTML tags to do the tiling.
+ *
+ * Items in TDataList can be in one of the three status: normal browsing,
+ * being editted and being selected. To change the status of a particular
+ * item, set {@link setSelectedItemIndex SelectedItemIndex} or
+ * {@link setEditItemIndex EditItemIndex}. The former will change
+ * the indicated item to selected mode, which will cause the item to
+ * use {@link setSelectedItemTemplate SelectedItemTemplate} or
+ * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
+ * The latter will change the indicated item to edit mode and to use corresponding
+ * template or renderer.
+ * Note, if an item is in edit mode, then selecting this item will have no effect.
+ *
+ * Different styles may be applied to items in different status. The style
+ * application is performed in a hierarchical way: Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * - item's own style
+ * - {@link getItemStyle ItemStyle}
+ * - {@link getAlternatingItemStyle AlternatingItemStyle}
+ * - {@link getSelectedItemStyle SelectedItemStyle}
+ * - {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ *
+ * When a page containing a datalist is post back, the datalist will restore automatically
+ * all its contents, including items, header, footer and separators.
+ * However, the data row associated with each item will not be recovered and become null.
+ * To access the data, use one of the following ways:
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datalist item and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
+ * Be aware though, if the size of your dataset is big, your page size will become big. Some
+ * complex data may also have serializing problem if saved in viewstate.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
+{
+ /**
+ * Command name that TDataList understands. They are case-insensitive.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+
+ /**
+ * @var TDataListItemCollection item list
+ */
+ private $_items=null;
+ /**
+ * @var Itemplate various item templates
+ */
+ private $_itemTemplate=null;
+ private $_emptyTemplate=null;
+ private $_alternatingItemTemplate=null;
+ private $_selectedItemTemplate=null;
+ private $_editItemTemplate=null;
+ private $_headerTemplate=null;
+ private $_footerTemplate=null;
+ private $_separatorTemplate=null;
+ /**
+ * @var TControl header item
+ */
+ private $_header=null;
+ /**
+ * @var TControl footer item
+ */
+ private $_footer=null;
+
+ /**
+ * @return TDataListItemCollection item list
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataListItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * @return string the class name for datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist items.
+ * This property takes precedence over {@link getItemTemplate ItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setItemTemplate
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getAlternatingItemRenderer()
+ {
+ return $this->getViewState('AlternatingItemRenderer','');
+ }
+
+ /**
+ * Sets the alternative item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as alternative datalist items.
+ * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setAlternatingItemTemplate
+ * @since 3.1.0
+ */
+ public function setAlternatingItemRenderer($value)
+ {
+ $this->setViewState('AlternatingItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being editted.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEditItemTemplate
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSelectedItemRenderer()
+ {
+ return $this->getViewState('SelectedItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being selected.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSelectedItemTemplate
+ * @since 3.1.0
+ */
+ public function setSelectedItemRenderer($value)
+ {
+ $this->setViewState('SelectedItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSeparatorRenderer()
+ {
+ return $this->getViewState('SeparatorRenderer','');
+ }
+
+ /**
+ * Sets the datalist item separator renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist item separators.
+ * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSeparatorTemplate
+ * @since 3.1.0
+ */
+ public function setSeparatorRenderer($value)
+ {
+ $this->setViewState('SeparatorRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist header item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the datalist header renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist header item.
+ * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setHeaderTemplate
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the datalist footer renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist footer item.
+ * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setFooterTemplate
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEmptyRenderer()
+ {
+ return $this->getViewState('EmptyRenderer','');
+ }
+
+ /**
+ * Sets the datalist empty renderer class.
+ *
+ * The empty renderer is created as the child of the datalist
+ * if data bound to the datalist is empty.
+ * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEmptyTemplate
+ * @since 3.1.0
+ */
+ public function setEmptyRenderer($value)
+ {
+ $this->setViewState('EmptyRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the template for item
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the template for each alternating item
+ */
+ public function getAlternatingItemTemplate()
+ {
+ return $this->_alternatingItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for each alternating item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setAlternatingItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_alternatingItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the selected item template
+ */
+ public function getSelectedItemTemplate()
+ {
+ return $this->_selectedItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the selected item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSelectedItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_selectedItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the edit item template
+ */
+ public function getEditItemTemplate()
+ {
+ return $this->_editItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the edit item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEditItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_editItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datalist
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datalist
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
+ }
+
+ /**
+ * @return ITemplate the separator template
+ */
+ public function getSeparatorTemplate()
+ {
+ return $this->_separatorTemplate;
+ }
+
+ /**
+ * @param ITemplate the separator template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSeparatorTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_separatorTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for separator
+ */
+ public function getSeparatorStyle()
+ {
+ if(($style=$this->getViewState('SeparatorStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SeparatorStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TControl the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return mixed the key value of the currently selected item
+ * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
+ */
+ public function getSelectedDataKey()
+ {
+ if($this->getDataKeyField()==='')
+ throw new TInvalidOperationException('datalist_datakeyfield_required');
+ $index=$this->getSelectedItemIndex();
+ $dataKeys=$this->getDataKeys();
+ if($index>=0 && $index<$dataKeys->getCount())
+ return $dataKeys->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return TControl the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether the header should be shown. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether to show header
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be shown. Defaults to true.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',true);
+ }
+
+ /**
+ * @param boolean whether to show footer
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TRepeatInfo repeat information (primarily used by control developers)
+ */
+ protected function getRepeatInfo()
+ {
+ if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
+ {
+ $repeatInfo=new TRepeatInfo;
+ $this->setViewState('RepeatInfo',$repeatInfo,null);
+ }
+ return $repeatInfo;
+ }
+
+ /**
+ * @return string caption of the table layout
+ */
+ public function getCaption()
+ {
+ return $this->getRepeatInfo()->getCaption();
+ }
+
+ /**
+ * @param string caption of the table layout
+ */
+ public function setCaption($value)
+ {
+ $this->getRepeatInfo()->setCaption($value);
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getRepeatInfo()->getCaptionAlign();
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->getRepeatInfo()->setCaptionAlign($value);
+ }
+
+ /**
+ * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->getRepeatInfo()->getRepeatColumns();
+ }
+
+ /**
+ * @param integer the number of columns that the list should be displayed with.
+ */
+ public function setRepeatColumns($value)
+ {
+ $this->getRepeatInfo()->setRepeatColumns($value);
+ }
+
+ /**
+ * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
+ */
+ public function getRepeatDirection()
+ {
+ return $this->getRepeatInfo()->getRepeatDirection();
+ }
+
+ /**
+ * @param TRepeatDirection the direction of traversing the list
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->getRepeatInfo()->setRepeatDirection($value);
+ }
+
+ /**
+ * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->getRepeatInfo()->getRepeatLayout();
+ }
+
+ /**
+ * @param TRepeatLayout how the list should be displayed, using table or using line breaks
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->getRepeatInfo()->setRepeatLayout($value);
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * datalist items and their child controls.
+ * If the event parameter is {@link TDataListCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataListCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ if(($item=$param->getItem()) instanceof IItemDataRenderer)
+ $this->setSelectedItemIndex($item->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Raises OnItemCreated event.
+ * This method is invoked after a data list item is created and instantiated with
+ * template, but before added to the page hierarchy.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises OnItemDataBound event.
+ * This method is invoked right after an item is data bound.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises OnItemCommand event.
+ * This method is invoked when a child control of the data list
+ * raises an OnCommand event.
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnEditCommand event.
+ * This method is invoked when a child control of the data list
+ * raises an OnCommand event and the command name is 'edit' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnDeleteCommand event.
+ * This method is invoked when a child control of the data list
+ * raises an OnCommand event and the command name is 'delete' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnUpdateCommand event.
+ * This method is invoked when a child control of the data list
+ * raises an OnCommand event and the command name is 'update' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises OnCancelCommand event.
+ * This method is invoked when a child control of the data list
+ * raises an OnCommand event and the command name is 'cancel' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether this control contains header item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has header
+ */
+ public function getHasHeader()
+ {
+ return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains footer item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has footer
+ */
+ public function getHasFooter()
+ {
+ return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains separator items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasSeparators()
+ {
+ return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ }
+
+ /**
+ * Returns a style used for rendering items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer index of the item being rendered
+ * @return TStyle item style
+ */
+ public function generateItemStyle($itemType,$index)
+ {
+ if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
+ {
+ $style=$item->getStyle();
+ $item->clearStyle();
+ return $style;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Renders an item in the list.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param THtmlWriter writer for rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the item in the item list
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index)
+ {
+ $item=$this->getItem($itemType,$index);
+ if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
+ $item->setTagName('div');
+ $item->renderControl($writer);
+ }
+
+ /**
+ * @param TListItemType item type
+ * @param integer item index
+ * @return TControl data list item with the specified item type and index
+ */
+ private function getItem($itemType,$index)
+ {
+ switch($itemType)
+ {
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ case TListItemType::EditItem:
+ return $this->getItems()->itemAt($index);
+ case TListItemType::Header:
+ return $this->getControls()->itemAt(0);
+ case TListItemType::Footer:
+ return $this->getControls()->itemAt($this->getControls()->getCount()-1);
+ case TListItemType::Separator:
+ $i=$index+$index+1;
+ if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
+ $i++;
+ return $this->getControls()->itemAt($i);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a datalist item.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemInternal($itemIndex,$itemType)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a datalist item and performs databinding.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @param mixed data to be associated with the item
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ if($item instanceof IDataRenderer)
+ $item->setData($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ private function getAlternatingItemDisplay()
+ {
+ if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return array($classPath,$this->_alternatingItemTemplate);
+ }
+
+ private function getSelectedItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
+ {
+ if($itemIndex%2===0)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return $this->getAlternatingItemDisplay();
+ }
+ else
+ return array($classPath,$this->_selectedItemTemplate);
+ }
+
+ private function getEditItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
+ return $this->getSelectedItemDisplay($itemIndex);
+ else
+ return array($classPath,$this->_editItemTemplate);
+ }
+
+ /**
+ * Creates a datalist item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TControl created datalist item
+ */
+ protected function createItem($itemIndex,$itemType)
+ {
+ $template=null;
+ $classPath=null;
+ switch($itemType)
+ {
+ case TListItemType::Item :
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ break;
+ case TListItemType::AlternatingItem :
+ list($classPath,$template)=$this->getAlternatingItemDisplay();
+ break;
+ case TListItemType::SelectedItem:
+ list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
+ break;
+ case TListItemType::EditItem:
+ list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
+ break;
+ case TListItemType::Header :
+ $classPath=$this->getHeaderRenderer();
+ $template=$this->_headerTemplate;
+ break;
+ case TListItemType::Footer :
+ $classPath=$this->getFooterRenderer();
+ $template=$this->_footerTemplate;
+ break;
+ case TListItemType::Separator :
+ $classPath=$this->getSeparatorRenderer();
+ $template=$this->_separatorTemplate;
+ break;
+ default:
+ throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
+ }
+ if($classPath!=='')
+ {
+ $item=Prado::createComponent($classPath);
+ if($item instanceof IItemDataRenderer)
+ {
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ }
+ }
+ else if($template!==null)
+ {
+ $item=new TDataListItem;
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ $template->instantiateIn($item);
+ }
+ else
+ $item=null;
+
+ return $item;
+ }
+
+ /**
+ * Creates empty datalist content.
+ */
+ protected function createEmptyContent()
+ {
+ if(($classPath=$this->getEmptyRenderer())!=='')
+ $this->getControls()->add(Prado::createComponent($classPath));
+ else if($this->_emptyTemplate!==null)
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ // apply header style if any
+ if($this->_header!==null && $this->_header instanceof IStyleable)
+ {
+ if($headerStyle=$this->getViewState('HeaderStyle',null))
+ $this->_header->getStyle()->mergeWith($headerStyle);
+ }
+
+ // apply footer style if any
+ if($this->_footer!==null && $this->_footer instanceof IStyleable)
+ {
+ if($footerStyle=$this->getViewState('FooterStyle',null))
+ $this->_footer->getStyle()->mergeWith($footerStyle);
+ }
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+
+ // apply item styles if any
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($index===$editIndex)
+ $style=$editItemStyle;
+ else if($index===$selectedIndex)
+ $style=$selectedItemStyle;
+ else if($index%2===0)
+ $style=$itemStyle;
+ else
+ $style=$alternatingItemStyle;
+ if($style && $item instanceof IStyleable)
+ $item->getStyle()->mergeWith($style);
+ }
+
+ // apply separator style if any
+ if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
+ {
+ $controls=$this->getControls();
+ $count=$controls->getCount();
+ for($i=$this->_header?2:1;$i<$count;$i+=2)
+ {
+ if(($separator=$controls->itemAt($i)) instanceof IStyleable)
+ $separator->getStyle()->mergeWith($separatorStyle);
+ }
+ }
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getIsDataBound())
+ $this->restoreItemsFromViewState();
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Clears up all items in the data list.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ }
+
+ /**
+ * Creates data list items based on viewstate information.
+ */
+ protected function restoreItemsFromViewState()
+ {
+ $this->reset();
+ if(($itemCount=$this->getViewState('ItemCount',0))>0)
+ {
+ $items=$this->getItems();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $this->_header=$this->createItemInternal(-1,TListItemType::Header);
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($hasSeparator && $i>0)
+ $this->createItemInternal($i-1,TListItemType::Separator);
+ if($i===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($i===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemInternal($i,$itemType));
+ }
+ $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
+ }
+ else
+ $this->createEmptyContent();
+ $this->clearChildState();
+ }
+
+ /**
+ * Performs databinding to populate data list items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+ $itemIndex=0;
+ $items=$this->getItems();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$dataItem)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
+ else
+ $keys->add($key);
+ if($itemIndex===0)
+ $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
+ if($hasSeparator && $itemIndex>0)
+ $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
+ if($itemIndex===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($itemIndex===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
+ $itemIndex++;
+ }
+ if($itemIndex>0)
+ $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
+ else
+ {
+ $this->createEmptyContent();
+ $this->dataBindChildren();
+ }
+ $this->setViewState('ItemCount',$itemIndex,0);
+ }
+
+ /**
+ * Renders the data list control.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ if($this->getItemCount()>0)
+ {
+ $this->applyItemStyles();
+ $repeatInfo=$this->getRepeatInfo();
+ $repeatInfo->renderRepeater($writer,$this);
+ }
+ else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
+ parent::render($writer);
+ }
+ }
+}
+
+
+/**
+ * TDataListItemEventParameter class
+ *
+ * TDataListItemEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemEventParameter extends TEventParameter
+{
+ /**
+ * The datalist item control responsible for the event.
+ * @var TControl
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TControl DataList item related with the corresponding event
+ */
+ public function __construct($item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TControl datalist item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataListCommandEventParameter class
+ *
+ * TDataListCommandEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
+ *
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TControl the datalist item control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the OnCommand event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl datalist item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TControl the datalist item control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the OnCommand event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataListItem class
+ *
+ * A TDataListItem control represents an item in the {@link TDataList} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of DataList
+ */
+ private $_itemIndex;
+ /**
+ * type of the TDataListItem
+ * @var TListItemType
+ */
+ private $_itemType;
+ /**
+ * value of the data associated with this item
+ * @var mixed
+ */
+ private $_data;
+
+ private $_tagName='span';
+
+ /**
+ * Returns the tag name used for this control.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return $this->_tagName;
+ }
+
+ /**
+ * @param string tag name of the control to be rendered
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=$value;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by a datalist item.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datalist
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for OnCommand event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+/**
+ * TDataListItemCollection class.
+ *
+ * TDataListItemCollection represents a collection of data list items.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TControl descendants.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataListItemRenderer.php b/framework/Web/UI/WebControls/TDataListItemRenderer.php
index 7065dc09..53c48b6e 100644
--- a/framework/Web/UI/WebControls/TDataListItemRenderer.php
+++ b/framework/Web/UI/WebControls/TDataListItemRenderer.php
@@ -1,172 +1,172 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataList');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataListItemRenderer class
- *
- * TDataListItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataList}.
- *
- * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
- * the bubbling scheme for the OnCommand event of data list items.
- *
- * TDataListItemRenderer also implements the {@link IStyleable} interface,
- * which allows TDataList to apply CSS styles to the renders.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
-{
- /**
- * Creates a style object to be used by the control.
- * This method may be overriden by controls to provide customized style.
- * @return TStyle
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return boolean whether the control has defined any style information
- */
- public function getHasStyle()
- {
- return $this->getViewState('Style',null)!==null;
- }
-
- /**
- * @return TStyle the object representing the css style of the control
- */
- public function getStyle()
- {
- if($style=$this->getViewState('Style',null))
- return $style;
- else
- {
- $style=$this->createStyle();
- $this->setViewState('Style',$style,null);
- return $style;
- }
- }
-
- /**
- * Removes all style data.
- */
- public function clearStyle()
- {
- $this->clearViewState('Style');
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for OnCommand event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * Returns the tag name used for this control.
- * By default, the tag name is 'span'.
- * You can override this method to provide customized tag names.
- * If the tag name is empty, the opening and closing tag will NOT be rendered.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * By default, this method renders the style string.
- * The method can be overriden to provide customized attribute rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- if($style=$this->getViewState('Style',null))
- $style->addAttributesToRender($writer);
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by replacing it with
- * the following sequence:
- * - {@link renderBeginTag}
- * - {@link renderContents}
- * - {@link renderEndTag}
- * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getTagName()!=='')
- {
- $this->renderBeginTag($writer);
- $this->renderContents($writer);
- $this->renderEndTag($writer);
- }
- else
- $this->renderContents($writer);
- }
-
- /**
- * Renders the openning tag for the control (including attributes)
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag($this->getTagName());
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * By default, child controls and text strings will be rendered.
- * You can override this method to provide customized content rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- parent::renderChildren($writer);
- }
-
- /**
- * Renders the closing tag for the control
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- $writer->renderEndTag();
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataListItemRenderer class
+ *
+ * TDataListItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataList}.
+ *
+ * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
+ * the bubbling scheme for the OnCommand event of data list items.
+ *
+ * TDataListItemRenderer also implements the {@link IStyleable} interface,
+ * which allows TDataList to apply CSS styles to the renders.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
+{
+ /**
+ * Creates a style object to be used by the control.
+ * This method may be overriden by controls to provide customized style.
+ * @return TStyle
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return boolean whether the control has defined any style information
+ */
+ public function getHasStyle()
+ {
+ return $this->getViewState('Style',null)!==null;
+ }
+
+ /**
+ * @return TStyle the object representing the css style of the control
+ */
+ public function getStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style;
+ else
+ {
+ $style=$this->createStyle();
+ $this->setViewState('Style',$style,null);
+ return $style;
+ }
+ }
+
+ /**
+ * Removes all style data.
+ */
+ public function clearStyle()
+ {
+ $this->clearViewState('Style');
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for OnCommand event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns the tag name used for this control.
+ * By default, the tag name is 'span'.
+ * You can override this method to provide customized tag names.
+ * If the tag name is empty, the opening and closing tag will NOT be rendered.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * By default, this method renders the style string.
+ * The method can be overriden to provide customized attribute rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($style=$this->getViewState('Style',null))
+ $style->addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by replacing it with
+ * the following sequence:
+ * - {@link renderBeginTag}
+ * - {@link renderContents}
+ * - {@link renderEndTag}
+ * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getTagName()!=='')
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+ else
+ $this->renderContents($writer);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * By default, child controls and text strings will be rendered.
+ * You can override this method to provide customized content rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ $writer->renderEndTag();
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataRenderer.php b/framework/Web/UI/WebControls/TDataRenderer.php
index ece9d974..44ab0b1d 100644
--- a/framework/Web/UI/WebControls/TDataRenderer.php
+++ b/framework/Web/UI/WebControls/TDataRenderer.php
@@ -1,52 +1,52 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-
-/**
- * TDataRenderer class
- *
- * TDataRenderer is the convenient base class for template-based renderer controls.
- * It extends {@link TTemplateControl} and implements the methods required
- * by the {@link IDataRenderer} interface.
- *
- * The following property is provided by TDataRenderer:
- * - {@link getData Data}: data associated with this renderer.
-
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
-{
- /**
- * @var mixed data associated with this renderer
- */
- private $_data;
-
- /**
- * @return mixed data associated with the item
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+
+/**
+ * TDataRenderer class
+ *
+ * TDataRenderer is the convenient base class for template-based renderer controls.
+ * It extends {@link TTemplateControl} and implements the methods required
+ * by the {@link IDataRenderer} interface.
+ *
+ * The following property is provided by TDataRenderer:
+ * - {@link getData Data}: data associated with this renderer.
+
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
+{
+ /**
+ * @var mixed data associated with this renderer
+ */
+ private $_data;
+
+ /**
+ * @return mixed data associated with the item
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataSourceControl.php b/framework/Web/UI/WebControls/TDataSourceControl.php
index 0b07810a..f7a224af 100644
--- a/framework/Web/UI/WebControls/TDataSourceControl.php
+++ b/framework/Web/UI/WebControls/TDataSourceControl.php
@@ -1,118 +1,118 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * IDataSource class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-interface IDataSource
-{
- public function getView($viewName);
- public function getViewNames();
- public function onDataSourceChanged($param);
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceControl extends TControl implements IDataSource
-{
- public function getView($viewName)
- {
- return null;
- }
-
- public function getViewNames()
- {
- return array();
- }
-
- public function onDataSourceChanged($param)
- {
- $this->raiseEvent('OnDataSourceChanged',$this,$param);
- }
-
- public function focus()
- {
- throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
- }
-
- public function getEnableTheming()
- {
- return false;
- }
-
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
- }
-
- public function getSkinID()
- {
- return '';
- }
-
- public function setSkinID($value)
- {
- throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
- }
-
- public function getVisible($checkParents=true)
- {
- return false;
- }
-
- public function setVisible($value)
- {
- throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
- }
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSource extends TDataSourceControl
-{
- private $_dataSource;
- private $_dataMember;
-
- public function __construct($dataSource,$dataMember)
- {
- if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
- throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
- $this->_dataSource=$dataSource;
- $this->_dataMember=$dataMember;
- }
-
- public function getView($viewName)
- {
- if($this->_dataSource instanceof IDataSource)
- return $this->_dataSource->getView($viewName);
- else
- return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * IDataSource class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+interface IDataSource
+{
+ public function getView($viewName);
+ public function getViewNames();
+ public function onDataSourceChanged($param);
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceControl extends TControl implements IDataSource
+{
+ public function getView($viewName)
+ {
+ return null;
+ }
+
+ public function getViewNames()
+ {
+ return array();
+ }
+
+ public function onDataSourceChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceChanged',$this,$param);
+ }
+
+ public function focus()
+ {
+ throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
+ }
+
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
+ }
+
+ public function getSkinID()
+ {
+ return '';
+ }
+
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
+ }
+
+ public function getVisible($checkParents=true)
+ {
+ return false;
+ }
+
+ public function setVisible($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
+ }
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSource extends TDataSourceControl
+{
+ private $_dataSource;
+ private $_dataMember;
+
+ public function __construct($dataSource,$dataMember)
+ {
+ if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
+ throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
+ $this->_dataSource=$dataSource;
+ $this->_dataMember=$dataMember;
+ }
+
+ public function getView($viewName)
+ {
+ if($this->_dataSource instanceof IDataSource)
+ return $this->_dataSource->getView($viewName);
+ else
+ return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataSourceView.php b/framework/Web/UI/WebControls/TDataSourceView.php
index 9e7c0128..af817a32 100644
--- a/framework/Web/UI/WebControls/TDataSourceView.php
+++ b/framework/Web/UI/WebControls/TDataSourceView.php
@@ -1,206 +1,206 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataSourceSelectParameters class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataSourceSelectParameters extends TComponent
-{
- private $_retrieveTotalRowCount=false;
- private $_startRowIndex=0;
- private $_totalRowCount=0;
- private $_maximumRows=0;
-
- public function getStartRowIndex()
- {
- return $this->_startRowIndex;
- }
-
- public function setStartRowIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_startRowIndex=$value;
- }
-
- public function getMaximumRows()
- {
- return $this->_maximumRows;
- }
-
- public function setMaximumRows($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_maximumRows=$value;
- }
-
- public function getRetrieveTotalRowCount()
- {
- return $this->_retrieveTotalRowCount;
- }
-
- public function setRetrieveTotalRowCount($value)
- {
- $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
- }
-
- public function getTotalRowCount()
- {
- return $this->_totalRowCount;
- }
-
- public function setTotalRowCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_totalRowCount=$value;
- }
-}
-
-/**
- * TDataSourceView class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceView extends TComponent
-{
- private $_owner;
- private $_name;
-
- public function __construct(IDataSource $owner,$viewName)
- {
- $this->_owner=$owner;
- $this->_name=$viewName;
- }
-
- /**
- * Performs DB selection based on specified parameters.
- * @param ???
- * @return Traversable
- */
- abstract public function select($parameters);
-
- /**
- * Inserts a DB record.
- * @param array|TMap
- * @return integer affected rows
- */
- public function insertAt($values)
- {
- throw new TNotSupportedException('datasourceview_insert_unsupported');
- }
-
- /**
- * Updates DB record(s) with the specified keys and new values
- * @param array|TMap keys for specifying the records to be updated
- * @param array|TMap new values
- * @return integer affected rows
- */
- public function update($keys,$values)
- {
- throw new TNotSupportedException('datasourceview_update_unsupported');
- }
-
- /**
- * Deletes DB row(s) with the specified keys.
- * @param array|TMap keys for specifying the rows to be deleted
- * @return integer affected rows
- */
- public function delete($keys)
- {
- throw new TNotSupportedException('datasourceview_delete_unsupported');
- }
-
- public function getCanDelete()
- {
- return false;
- }
-
- public function getCanInsert()
- {
- return false;
- }
-
- public function getCanPage()
- {
- return false;
- }
-
- public function getCanGetRowCount()
- {
- return false;
- }
-
- public function getCanSort()
- {
- return false;
- }
-
- public function getCanUpdate()
- {
- return false;
- }
-
- public function getName()
- {
- return $this->_name;
- }
-
- public function getDataSource()
- {
- return $this->_owner;
- }
-
- public function onDataSourceViewChanged($param)
- {
- $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
- }
-}
-
-/**
- * TReadOnlyDataSourceView class
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSourceView extends TDataSourceView
-{
- private $_dataSource=null;
-
- public function __construct(IDataSource $owner,$viewName,$dataSource)
- {
- parent::__construct($owner,$viewName);
- if($dataSource===null || is_array($dataSource))
- $this->_dataSource=new TMap($dataSource);
- else if($dataSource instanceof Traversable)
- $this->_dataSource=$dataSource;
- else
- throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
- }
-
- public function select($parameters)
- {
- return $this->_dataSource;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataSourceSelectParameters class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataSourceSelectParameters extends TComponent
+{
+ private $_retrieveTotalRowCount=false;
+ private $_startRowIndex=0;
+ private $_totalRowCount=0;
+ private $_maximumRows=0;
+
+ public function getStartRowIndex()
+ {
+ return $this->_startRowIndex;
+ }
+
+ public function setStartRowIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_startRowIndex=$value;
+ }
+
+ public function getMaximumRows()
+ {
+ return $this->_maximumRows;
+ }
+
+ public function setMaximumRows($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_maximumRows=$value;
+ }
+
+ public function getRetrieveTotalRowCount()
+ {
+ return $this->_retrieveTotalRowCount;
+ }
+
+ public function setRetrieveTotalRowCount($value)
+ {
+ $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
+ }
+
+ public function getTotalRowCount()
+ {
+ return $this->_totalRowCount;
+ }
+
+ public function setTotalRowCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_totalRowCount=$value;
+ }
+}
+
+/**
+ * TDataSourceView class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceView extends TComponent
+{
+ private $_owner;
+ private $_name;
+
+ public function __construct(IDataSource $owner,$viewName)
+ {
+ $this->_owner=$owner;
+ $this->_name=$viewName;
+ }
+
+ /**
+ * Performs DB selection based on specified parameters.
+ * @param ???
+ * @return Traversable
+ */
+ abstract public function select($parameters);
+
+ /**
+ * Inserts a DB record.
+ * @param array|TMap
+ * @return integer affected rows
+ */
+ public function insertAt($values)
+ {
+ throw new TNotSupportedException('datasourceview_insert_unsupported');
+ }
+
+ /**
+ * Updates DB record(s) with the specified keys and new values
+ * @param array|TMap keys for specifying the records to be updated
+ * @param array|TMap new values
+ * @return integer affected rows
+ */
+ public function update($keys,$values)
+ {
+ throw new TNotSupportedException('datasourceview_update_unsupported');
+ }
+
+ /**
+ * Deletes DB row(s) with the specified keys.
+ * @param array|TMap keys for specifying the rows to be deleted
+ * @return integer affected rows
+ */
+ public function delete($keys)
+ {
+ throw new TNotSupportedException('datasourceview_delete_unsupported');
+ }
+
+ public function getCanDelete()
+ {
+ return false;
+ }
+
+ public function getCanInsert()
+ {
+ return false;
+ }
+
+ public function getCanPage()
+ {
+ return false;
+ }
+
+ public function getCanGetRowCount()
+ {
+ return false;
+ }
+
+ public function getCanSort()
+ {
+ return false;
+ }
+
+ public function getCanUpdate()
+ {
+ return false;
+ }
+
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ public function getDataSource()
+ {
+ return $this->_owner;
+ }
+
+ public function onDataSourceViewChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
+ }
+}
+
+/**
+ * TReadOnlyDataSourceView class
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSourceView extends TDataSourceView
+{
+ private $_dataSource=null;
+
+ public function __construct(IDataSource $owner,$viewName,$dataSource)
+ {
+ parent::__construct($owner,$viewName);
+ if($dataSource===null || is_array($dataSource))
+ $this->_dataSource=new TMap($dataSource);
+ else if($dataSource instanceof Traversable)
+ $this->_dataSource=$dataSource;
+ else
+ throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
+ }
+
+ public function select($parameters)
+ {
+ return $this->_dataSource;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php
index 24372565..0e412e24 100644
--- a/framework/Web/UI/WebControls/TDataTypeValidator.php
+++ b/framework/Web/UI/WebControls/TDataTypeValidator.php
@@ -1,141 +1,141 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TDataTypeValidator class
- *
- * TDataTypeValidator verifies if the input data is of the type specified
- * by {@link setDataType DataType}.
- * The following data types are supported:
- * - Integer A 32-bit signed integer data type.
- * - Float A double-precision floating point number data type.
- * - Date A date data type.
- * - String A string data type.
- * For Date type, the property {@link setDateFormat DateFormat}
- * will be used to determine how to parse the date string. If it is not
- * provided, the string will be assumed to be in GNU datetime format.
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataTypeValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDataTypeValidator';
- }
-
- /**
- * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType','String');
- }
-
- /**
- * Sets the data type that the values being compared are converted to before the comparison is made.
- * @param TValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
-
- /**
- * Determine if the given value is of a particular type using RegExp.
- * @param string value to check
- * @return boolean true if value fits the type expression.
- */
- protected function evaluateDataTypeCheck($value)
- {
- if($value=='')
- return true;
-
- switch($this->getDataType())
- {
- case TValidationDataType::Integer:
- return preg_match('/^[-+]?[0-9]+$/',trim($value));
- case TValidationDataType::Float:
- return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
- case TValidationDataType::Date:
- $dateFormat = $this->getDateFormat();
- if(strlen($dateFormat))
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
- return $formatter->isValidDate($value);
- }
- else
- return strtotime($value) > 0;
- }
- return true;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['DataType']=$this->getDataType();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data is of valid type.
- * The validation always succeeds if ControlToValidate is not specified
- * or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
-
- return $this->evaluateDataTypeCheck($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TDataTypeValidator class
+ *
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by {@link setDataType DataType}.
+ * The following data types are supported:
+ * - Integer A 32-bit signed integer data type.
+ * - Float A double-precision floating point number data type.
+ * - Date A date data type.
+ * - String A string data type.
+ * For Date type, the property {@link setDateFormat DateFormat}
+ * will be used to determine how to parse the date string. If it is not
+ * provided, the string will be assumed to be in GNU datetime format.
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataTypeValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDataTypeValidator';
+ }
+
+ /**
+ * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType','String');
+ }
+
+ /**
+ * Sets the data type that the values being compared are converted to before the comparison is made.
+ * @param TValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+
+ /**
+ * Determine if the given value is of a particular type using RegExp.
+ * @param string value to check
+ * @return boolean true if value fits the type expression.
+ */
+ protected function evaluateDataTypeCheck($value)
+ {
+ if($value=='')
+ return true;
+
+ switch($this->getDataType())
+ {
+ case TValidationDataType::Integer:
+ return preg_match('/^[-+]?[0-9]+$/',trim($value));
+ case TValidationDataType::Float:
+ return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
+ case TValidationDataType::Date:
+ $dateFormat = $this->getDateFormat();
+ if(strlen($dateFormat))
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
+ return $formatter->isValidDate($value);
+ }
+ else
+ return strtotime($value) > 0;
+ }
+ return true;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['DataType']=$this->getDataType();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data is of valid type.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+
+ return $this->evaluateDataTypeCheck($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php
index 8d1a811c..866bc585 100644
--- a/framework/Web/UI/WebControls/TDatePicker.php
+++ b/framework/Web/UI/WebControls/TDatePicker.php
@@ -1,993 +1,993 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTextBox class
- */
-Prado::using('System.Web.UI.WebControls.TTextBox');
-
-/**
- *
- * TDatePicker class.
- *
- * TDatePicker displays a text box for date input purpose.
- * When the text box receives focus, a calendar will pop up and users can
- * pick up from it a date that will be automatically entered into the text box.
- * The format of the date string displayed in the text box is determined by
- * the DateFormat property. Valid formats are the combination of the
- * following tokens,
- *
- *
- * Character Format Pattern (en-US)
- * -----------------------------------------
- * d day digit
- * dd padded day digit e.g. 01, 02
- * M month digit
- * MM padded month digit
- * MMMM localized month name, e.g. March, April
- * yy 2 digit year
- * yyyy 4 digit year
- * -----------------------------------------
- *
- *
- * TDatePicker has four Mode to show the date picker popup.
- *
- * # Basic -- Only shows a text input, focusing on the input shows the
- * date picker. This way you can access the popup using only
- * the keyboard. Note that because of this, TAB-bing through
- * this control will automatically select the current date if
- * no previous date was selected. If you close the popup (eg.
- * pressing the ESC key) you'll need to un-focus and re-focus
- * the control again for the popup to reappear.
- * # Clickable -- Only shows a text input, clicking on the input shows the
- * date picker. This mode solves the two small problems of the
- * Basic mode. It was first introduced in Prado 3.2.
- * # Button -- Shows a button next to the text input, clicking on the
- * button shows the date, button text can be by the
- * ButtonText property
- * # ImageButton -- Shows an image next to the text input, clicking on
- * the image shows the date picker, image source can be
- * change through the ButtonImageUrl property.
- *
- * The CssClass property can be used to override the css class name
- * for the date picker panel. CalendarStyle property sets the packages
- * styles available. E.g. default .
- *
- * The InputMode property can be set to "TextBox" or "DropDownList" with
- * default as "TextBox".
- * In DropDownList mode, in addition to the popup date picker, three
- * drop down list (day, month and year) are presented to select the date .
- *
- * The PositionMode property can be set to "Top" or "Bottom" with default
- * as "Bottom". It specifies the position of the calendar popup, relative to the
- * input field.
- *
- * @author Wei Zhuo
- * @author Carl G. Mathisen
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDatePicker extends TTextBox
-{
- /**
- * Script path relative to the TClientScriptManager::SCRIPT_PATH
- */
- const SCRIPT_PATH = 'prado/datepicker';
-
- /**
- * @var TDatePickerClientScript validator client-script options.
- */
- private $_clientScript;
- /**
- * AutoPostBack is not supported.
- */
- public function setAutoPostBack($value)
- {
- throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
- get_class($this));
- }
-
- /**
- * @return string the format of the date string
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat','dd-MM-yyyy');
- }
-
- /**
- * Sets the format of the date string.
- * @param string the format of the date string
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
- }
-
- /**
- * @return boolean whether the calendar window should pop up when the control receives focus
- */
- public function getShowCalendar()
- {
- return $this->getViewState('ShowCalendar',true);
- }
-
- /**
- * Sets whether to pop up the calendar window when the control receives focus
- * @param boolean whether to show the calendar window
- */
- public function setShowCalendar($value)
- {
- $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Gets the current culture.
- * @return string current culture, e.g. en_AU.
- */
- public function getCulture()
- {
- return $this->getViewState('Culture', '');
- }
-
- /**
- * Sets the culture/language for the date picker.
- * @param string a culture string, e.g. en_AU.
- */
- public function setCulture($value)
- {
- $this->setViewState('Culture', $value, '');
- }
-
- /**
- * @param TDatePickerInputMode input method of date values
- */
- public function setInputMode($value)
- {
- $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
- }
-
- /**
- * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
- */
- public function getInputMode()
- {
- return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
- }
-
- /**
- * @param TDatePickerMode calendar UI mode
- */
- public function setMode($value)
- {
- $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
- }
-
- /**
- * @return TDatePickerMode current calendar UI mode.
- */
- public function getMode()
- {
- return $this->getViewState('Mode', TDatePickerMode::Basic);
- }
- /**
- * @param string the image url for "Image" UI mode.
- */
- public function setButtonImageUrl($value)
- {
- $this->setViewState('ImageUrl', $value, '');
- }
-
- /**
- * @return string the image url for "Image" UI mode.
- */
- public function getButtonImageUrl()
- {
- return $this->getViewState('ImageUrl', '');
- }
-
- /**
- * @param string set the calendar style
- */
- public function setCalendarStyle($value)
- {
- $this->setViewState('CalendarStyle', $value, 'default');
- }
-
- /**
- * @return string current calendar style
- */
- public function getCalendarStyle()
- {
- return $this->getViewState('CalendarStyle', 'default');
- }
-
- /**
- * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
- * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
- */
- public function setFirstDayOfWeek($value)
- {
- $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
- }
-
- /**
- * @return integer first day of the week
- */
- public function getFirstDayOfWeek()
- {
- return $this->getViewState('FirstDayOfWeek', 1);
- }
-
- /**
- * @return string text for the date picker button. Default is "...".
- */
- public function getButtonText()
- {
- return $this->getViewState('ButtonText', '...');
- }
-
- /**
- * @param string text for the date picker button
- */
- public function setButtonText($value)
- {
- $this->setViewState('ButtonText', $value, '...');
- }
-
- /**
- * @param integer date picker starting year, default is 2000.
- */
- public function setFromYear($value)
- {
- $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
- }
-
- /**
- * @return integer date picker starting year, default is -5 years
- */
- public function getFromYear()
- {
- return $this->getViewState('FromYear', intval(@date('Y'))-5);
- }
-
- /**
- * @param integer date picker ending year, default +10 years
- */
- public function setUpToYear($value)
- {
- $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
- }
-
- /**
- * @return integer date picker ending year, default +10 years
- */
- public function getUpToYear()
- {
- return $this->getViewState('UpToYear', intval(@date('Y'))+10);
- }
-
- /**
- * @param TDatePickerPositionMode calendar UI position
- */
- public function setPositionMode($value)
- {
- $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return TDatePickerPositionMode current calendar UI position.
- */
- public function getPositionMode()
- {
- return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
- */
- public function getTimeStamp()
- {
- if(trim($this->getText())==='')
- return null;
- else
- return $this->getTimeStampFromText();
- }
-
- /**
- * Sets the date for the date picker using timestamp.
- * @param float time stamp for the date picker
- */
- public function setTimeStamp($value)
- {
- if($value===null || (is_string($value) && trim($value)===''))
- $this->setText('');
- else
- {
- $date = TPropertyValue::ensureFloat($value);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
- $this->setText($formatter->format($date));
- }
- }
-
- /**
- * Returns the timestamp selected by the user.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getTimeStamp()}.
- * @return integer the timestamp of the TDatePicker control.
- * @see getTimeStamp
- * @since 3.1.2
- */
- public function getData()
- {
- return $this->getTimeStamp();
- }
-
- /**
- * Sets the timestamp represented by this control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setTimeStamp()}.
- * @param integer the timestamp of the TDatePicker control.
- * @see setTimeStamp
- * @since 3.1.2
- */
- public function setData($value)
- {
- $this->setTimeStamp($value);
- }
-
- /**
- * @return string the date string.
- */
- public function getDate()
- {
- return $this->getText();
- }
-
- /**
- * @param string date string
- */
- public function setDate($value)
- {
- $this->setText($value);
- }
-
- /**
- * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
- *
- * The date picker on the client-side supports the following events.
- * # OnDateChanged -- raised when the date is changed.
- *
- * You can attach custom javascript code to each of these events
- *
- * @return TDatePickerClientScript javascript validator event options.
- */
- public function getClientSide()
- {
- if($this->_clientScript===null)
- $this->_clientScript = $this->createClientScript();
- return $this->_clientScript;
- }
-
- /**
- * @return TDatePickerClientScript javascript validator event options.
- */
- protected function createClientScript()
- {
- return new TDatePickerClientScript;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return integer the interger timestamp if valid, otherwise the original text.
- */
- public function getValidationPropertyValue()
- {
- if(($text = $this->getText()) === '')
- return '';
- $date = $this->getTimeStamp();
- return $date == null ? $text : $date;
- }
-
- /**
- * Publish the date picker Css asset files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getInputMode() === TDatePickerInputMode::DropDownList)
- {
- $page = $this->getPage();
- $uniqueID = $this->getUniqueID();
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year');
- }
- $this->publishCalendarStyle();
- $this->registerCalendarClientScriptPre();
- }
-
- /**
- * Renders body content.
- * This method overrides parent implementation by adding
- * additional date picker button if Mode is Button or ImageButton.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- {
- parent::render($writer);
- $this->renderDatePickerButtons($writer);
- }
- else
- {
- $this->renderDropDownListCalendar($writer);
- if($this->hasDayPattern())
- {
- $this->registerCalendarClientScriptPost();
- $this->renderDatePickerButtons($writer);
- }
- }
- }
-
- /**
- * Renders the date picker popup buttons.
- */
- protected function renderDatePickerButtons($writer)
- {
- if($this->getShowCalendar())
- {
- switch ($this->getMode())
- {
- case TDatePickerMode::Button:
- $this->renderButtonDatePicker($writer);
- break;
- case TDatePickerMode::ImageButton :
- $this->renderImageButtonDatePicker($writer);
- break;
- }
- }
- }
-
- /**
- * Loads user input data. Override parent implementation, when InputMode
- * is DropDownList call getDateFromPostData to get date data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- return parent::loadPostData($key, $values);
- $value = $this->getDateFromPostData($key, $values);
- if(!$this->getReadOnly() && $this->getText()!==$value)
- {
- $this->setText($value);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Loads date from drop down list data.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return array the date selected
- */
- protected function getDateFromPostData($key, $values)
- {
- $date = @getdate();
-
- if(isset($values[$key.'$day']))
- $day = intval($values[$key.'$day']);
- else
- $day = $date['mday'];
-
- if(isset($values[$key.'$month']))
- $month = intval($values[$key.'$month']) + 1;
- else
- $month = $date['mon'];
-
- if(isset($values[$key.'$year']))
- $year = intval($values[$key.'$year']);
- else
- $year = $date['year'];
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
- //$date = @mktime(0, 0, 0, $month, $day, $year);
-
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
- return $formatter->format($date);
- }
-
- /**
- * Get javascript date picker options.
- * @return array date picker client-side options
- */
- protected function getDatePickerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['InputMode'] = $this->getInputMode();
- $options['Format'] = $this->getDateFormat();
- $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
- if(($cssClass=$this->getCssClass())!=='')
- $options['ClassName'] = $cssClass;
- $options['CalendarStyle'] = $this->getCalendarStyle();
- $options['FromYear'] = $this->getFromYear();
- $options['UpToYear'] = $this->getUpToYear();
- switch($this->getMode())
- {
- case TDatePickerMode::Basic:
- break;
- case TDatePickerMode::Clickable:
- $options['TriggerEvent'] = "click";
- break;
- default:
- $options['Trigger'] = $this->getDatePickerButtonID();
- break;
- }
- $options['PositionMode'] = $this->getPositionMode();
-
- $options = array_merge($options, $this->getCulturalOptions());
- if($this->_clientScript!==null)
- $options = array_merge($options,
- $this->_clientScript->getOptions()->toArray());
- return $options;
- }
-
- /**
- * Get javascript localization options, e.g. month and weekday names.
- * @return array localization options.
- */
- protected function getCulturalOptions()
- {
- if($this->getCurrentCulture() == 'en')
- return array();
-
- $date = $this->getLocalizedCalendarInfo();
- $options['MonthNames'] = $date->getMonthNames();
- $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
- $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
-
- return $options;
- }
-
- /**
- * @return string the current culture, falls back to application if culture is not set.
- */
- protected function getCurrentCulture()
- {
- $app = $this->getApplication()->getGlobalization(false);
- return $this->getCulture() == '' ?
- ($app ? $app->getCulture() : 'en') : $this->getCulture();
- }
-
- /**
- * @return DateTimeFormatInfo date time format information for the current culture.
- */
- protected function getLocalizedCalendarInfo()
- {
- //expensive operations
- $culture = $this->getCurrentCulture();
- Prado::using('System.I18N.core.DateTimeFormatInfo');
- $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
- return $info->getDateTimeFormat();
- }
-
- /**
- * Renders the drop down list date picker.
- */
- protected function renderDropDownListCalendar($writer)
- {
- if($this->getMode() == TDatePickerMode::Basic)
- $this->setMode(TDatePickerMode::ImageButton);
- parent::addAttributesToRender($writer);
- $writer->removeAttribute('name');
- $writer->removeAttribute('type');
- $writer->addAttribute('id', $this->getClientID());
-
- if(strlen($class = $this->getCssClass()) > 0)
- $writer->addAttribute('class', $class);
- $writer->renderBeginTag('span');
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getDate($this->getTimeStampFromText());
- //$date = @getdate($this->getTimeStampFromText());
-
- $this->renderCalendarSelections($writer, $date);
-
- //render a hidden input field
- $writer->addAttribute('name', $this->getUniqueID());
- $writer->addAttribute('type', 'hidden');
- $writer->addAttribute('value', $this->getText());
- $writer->renderBeginTag('input');
-
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
-
- protected function hasDayPattern()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- return ($formatter->getDayPattern()!==null);
- }
-
- /**
- * Renders the calendar drop down list depending on the DateFormat pattern.
- * @param THtmlWriter the Html writer to render the drop down lists.
- * @param array the current selected date
- */
- protected function renderCalendarSelections($writer, $date)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
-
- foreach($formatter->getDayMonthYearOrdering() as $type)
- {
- if($type == 'day')
- $this->renderCalendarDayOptions($writer,$date['mday']);
- elseif($type == 'month')
- $this->renderCalendarMonthOptions($writer,$date['mon']);
- elseif($type == 'year')
- $this->renderCalendarYearOptions($writer,$date['year']);
- }
- }
-
- /**
- * Gets the date from the text input using TSimpleDateFormatter
- * @return integer current selected date timestamp
- */
- protected function getTimeStampFromText()
- {
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
- return $formatter->parse($this->getText());
- }
-
- /**
- * Renders a drop down lists.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param array list of selection options
- * @param mixed selected key.
- */
- private function renderDropDownListOptions($writer,$options,$selected=null)
- {
- foreach($options as $k => $v)
- {
- $writer->addAttribute('value', $k);
- if($k == $selected)
- $writer->addAttribute('selected', 'selected');
- $writer->renderBeginTag('option');
- $writer->write($v);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the day drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected day.
- */
- protected function renderCalendarDayOptions($writer, $selected=null)
- {
- $days = $this->getDropDownDayOptions();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
- $writer->addAttribute('class', 'datepicker_day_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer, $days, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * @return array list of day options for a drop down list.
- */
- protected function getDropDownDayOptions()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- $days = array();
- $requiresPadding = $formatter->getDayPattern() === 'dd';
- for($i=1;$i<=31;$i++)
- {
- $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
- }
- return $days;
- }
-
- /**
- * Renders the month drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected month.
- */
- protected function renderCalendarMonthOptions($writer, $selected=null)
- {
- $info = $this->getLocalizedCalendarInfo();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
- $writer->addAttribute('class', 'datepicker_month_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer,
- $this->getLocalizedMonthNames($info), $selected-1);
- $writer->renderEndTag();
- }
-
- /**
- * Returns the localized month names that depends on the month format pattern.
- * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
- * and "M" return month digits.
- * @param DateTimeFormatInfo localized date format information.
- * @return array localized month names.
- */
- protected function getLocalizedMonthNames($info)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- switch($formatter->getMonthPattern())
- {
- case 'MMM': return $info->getAbbreviatedMonthNames();
- case 'MM':
- $array = array();
- for($i=1;$i<=12;$i++)
- $array[$i-1] = $i < 10 ? '0'.$i : $i;
- return $array;
- case 'M':
- $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
- return $array;
- default : return $info->getMonthNames();
- }
- }
-
- /**
- * Renders the year drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected year.
- */
- protected function renderCalendarYearOptions($writer, $selected=null)
- {
- $years = array();
- for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
- $years[$i] = $i;
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $writer->addAttribute('class', 'datepicker_year_options');
- $this->renderDropDownListOptions($writer, $years, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * Gets the ID for the date picker trigger button.
- * @return string unique button ID
- */
- protected function getDatePickerButtonID()
- {
- return $this->getClientID().'button';
- }
-
- /**
- * Adds an additional button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderButtonDatePicker($writer)
- {
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('type', 'button');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
- $writer->addAttribute('value',$this->getButtonText());
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag("input");
- $writer->renderEndTag();
- }
-
- /**
- * Adds an additional image button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderImageButtonDatePicker($writer)
- {
- $url = $this->getButtonImageUrl();
- $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('src', $url);
- $writer->addAttribute('alt', ' ');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->addAttribute('type', 'image');
- $writer->addAttribute('onclick', 'return false;');
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * @param string date picker asset file in the self::SCRIPT_PATH directory.
- * @return string date picker asset url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Publish the calendar style Css asset file.
- * @return string Css file url.
- */
- protected function publishCalendarStyle()
- {
- $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- return $url;
- }
-
- /**
- * Add the client id to the input textbox, and register the client scripts.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->registerCalendarClientScriptPost();
- }
-
-
- /**
- * Registers the javascript code to initialize the date picker.
- */
- protected function registerCalendarClientScriptPre()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPradoScript("datepicker");
- }
- }
-
- protected function registerCalendarClientScriptPost()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
- {
- $spacer = $this->getAssetUrl('spacer.gif');
- $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
- $cs->registerEndScript('TDatePicker.spacer', $code);
- }
-
- $options = TJavaScript::encode($this->getDatePickerOptions());
- $code = "new Prado.WebUI.TDatePicker($options);";
- $cs->registerEndScript("prado:".$this->getClientID(), $code);
- }
- }
-}
-
-/**
- * TDatePickerClientScript class.
- *
- * Client-side date picker event {@link setOnDateChanged OnDateChanged}
- * can be modified through the {@link TDatePicker::getClientSide ClientSide}
- * property of a date picker.
- *
- * The OnDateChanged event is raise when the date picker's date
- * is changed.
- * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
- * as parameter to this event
- *
- * @author Wei Zhuo
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerClientScript extends TClientSideOptions
-{
- /**
- * Javascript code to execute when the date picker's date is changed.
- * @param string javascript code
- */
- public function setOnDateChanged($javascript)
- {
- $this->setFunction('OnDateChanged', $javascript);
- }
-
- /**
- * @return string javascript code to execute when the date picker's date is changed.
- */
- public function getOnDateChanged()
- {
- return $this->getOption('OnDateChanged');
- }
-}
-
-
-/**
- * TDatePickerInputMode class.
- * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
- *
- * The following enumerable values are defined:
- * - TextBox: text boxes are used to input date values
- * - DropDownList: dropdown lists are used to pick up date values
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerInputMode extends TEnumerable
-{
- const TextBox='TextBox';
- const DropDownList='DropDownList';
-}
-
-/**
- * TDatePickerMode class.
- * TDatePickerMode defines the enumerable type for the possible UI mode
- * that a {@link TDatePicker} control can take.
- *
- * The following enumerable values are defined:
- * - Basic: Only shows a text input, focusing on the input shows the date picker
- * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
- * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
- * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerMode extends TEnumerable
-{
- const Basic='Basic';
- const Clickable='Clickable';
- const Button='Button';
- const ImageButton='ImageButton';
-}
-
-/**
- * TDatePickerPositionMode class.
- * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
- *
- * The following enumerable values are defined:
- * - Top: the date picker is placed above the input field
- * - Bottom: the date picker is placed below the input field
- *
- * @author Carl G. Mathisen
- * @package System.Web.UI.WebControls
- * @since 3.1.4
- */
-class TDatePickerPositionMode extends TEnumerable
-{
- const Top='Top';
- const Bottom='Bottom';
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTextBox class
+ */
+Prado::using('System.Web.UI.WebControls.TTextBox');
+
+/**
+ *
+ * TDatePicker class.
+ *
+ * TDatePicker displays a text box for date input purpose.
+ * When the text box receives focus, a calendar will pop up and users can
+ * pick up from it a date that will be automatically entered into the text box.
+ * The format of the date string displayed in the text box is determined by
+ * the DateFormat property. Valid formats are the combination of the
+ * following tokens,
+ *
+ *
+ * Character Format Pattern (en-US)
+ * -----------------------------------------
+ * d day digit
+ * dd padded day digit e.g. 01, 02
+ * M month digit
+ * MM padded month digit
+ * MMMM localized month name, e.g. March, April
+ * yy 2 digit year
+ * yyyy 4 digit year
+ * -----------------------------------------
+ *
+ *
+ * TDatePicker has four Mode to show the date picker popup.
+ *
+ * # Basic -- Only shows a text input, focusing on the input shows the
+ * date picker. This way you can access the popup using only
+ * the keyboard. Note that because of this, TAB-bing through
+ * this control will automatically select the current date if
+ * no previous date was selected. If you close the popup (eg.
+ * pressing the ESC key) you'll need to un-focus and re-focus
+ * the control again for the popup to reappear.
+ * # Clickable -- Only shows a text input, clicking on the input shows the
+ * date picker. This mode solves the two small problems of the
+ * Basic mode. It was first introduced in Prado 3.2.
+ * # Button -- Shows a button next to the text input, clicking on the
+ * button shows the date, button text can be by the
+ * ButtonText property
+ * # ImageButton -- Shows an image next to the text input, clicking on
+ * the image shows the date picker, image source can be
+ * change through the ButtonImageUrl property.
+ *
+ * The CssClass property can be used to override the css class name
+ * for the date picker panel. CalendarStyle property sets the packages
+ * styles available. E.g. default .
+ *
+ * The InputMode property can be set to "TextBox" or "DropDownList" with
+ * default as "TextBox".
+ * In DropDownList mode, in addition to the popup date picker, three
+ * drop down list (day, month and year) are presented to select the date .
+ *
+ * The PositionMode property can be set to "Top" or "Bottom" with default
+ * as "Bottom". It specifies the position of the calendar popup, relative to the
+ * input field.
+ *
+ * @author Wei Zhuo
+ * @author Carl G. Mathisen
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDatePicker extends TTextBox
+{
+ /**
+ * Script path relative to the TClientScriptManager::SCRIPT_PATH
+ */
+ const SCRIPT_PATH = 'prado/datepicker';
+
+ /**
+ * @var TDatePickerClientScript validator client-script options.
+ */
+ private $_clientScript;
+ /**
+ * AutoPostBack is not supported.
+ */
+ public function setAutoPostBack($value)
+ {
+ throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * @return string the format of the date string
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat','dd-MM-yyyy');
+ }
+
+ /**
+ * Sets the format of the date string.
+ * @param string the format of the date string
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
+ }
+
+ /**
+ * @return boolean whether the calendar window should pop up when the control receives focus
+ */
+ public function getShowCalendar()
+ {
+ return $this->getViewState('ShowCalendar',true);
+ }
+
+ /**
+ * Sets whether to pop up the calendar window when the control receives focus
+ * @param boolean whether to show the calendar window
+ */
+ public function setShowCalendar($value)
+ {
+ $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. en_AU.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the date picker.
+ * @param string a culture string, e.g. en_AU.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * @param TDatePickerInputMode input method of date values
+ */
+ public function setInputMode($value)
+ {
+ $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
+ */
+ public function getInputMode()
+ {
+ return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @param TDatePickerMode calendar UI mode
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
+ }
+
+ /**
+ * @return TDatePickerMode current calendar UI mode.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode', TDatePickerMode::Basic);
+ }
+ /**
+ * @param string the image url for "Image" UI mode.
+ */
+ public function setButtonImageUrl($value)
+ {
+ $this->setViewState('ImageUrl', $value, '');
+ }
+
+ /**
+ * @return string the image url for "Image" UI mode.
+ */
+ public function getButtonImageUrl()
+ {
+ return $this->getViewState('ImageUrl', '');
+ }
+
+ /**
+ * @param string set the calendar style
+ */
+ public function setCalendarStyle($value)
+ {
+ $this->setViewState('CalendarStyle', $value, 'default');
+ }
+
+ /**
+ * @return string current calendar style
+ */
+ public function getCalendarStyle()
+ {
+ return $this->getViewState('CalendarStyle', 'default');
+ }
+
+ /**
+ * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
+ * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
+ */
+ public function setFirstDayOfWeek($value)
+ {
+ $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
+ }
+
+ /**
+ * @return integer first day of the week
+ */
+ public function getFirstDayOfWeek()
+ {
+ return $this->getViewState('FirstDayOfWeek', 1);
+ }
+
+ /**
+ * @return string text for the date picker button. Default is "...".
+ */
+ public function getButtonText()
+ {
+ return $this->getViewState('ButtonText', '...');
+ }
+
+ /**
+ * @param string text for the date picker button
+ */
+ public function setButtonText($value)
+ {
+ $this->setViewState('ButtonText', $value, '...');
+ }
+
+ /**
+ * @param integer date picker starting year, default is 2000.
+ */
+ public function setFromYear($value)
+ {
+ $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
+ }
+
+ /**
+ * @return integer date picker starting year, default is -5 years
+ */
+ public function getFromYear()
+ {
+ return $this->getViewState('FromYear', intval(@date('Y'))-5);
+ }
+
+ /**
+ * @param integer date picker ending year, default +10 years
+ */
+ public function setUpToYear($value)
+ {
+ $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
+ }
+
+ /**
+ * @return integer date picker ending year, default +10 years
+ */
+ public function getUpToYear()
+ {
+ return $this->getViewState('UpToYear', intval(@date('Y'))+10);
+ }
+
+ /**
+ * @param TDatePickerPositionMode calendar UI position
+ */
+ public function setPositionMode($value)
+ {
+ $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return TDatePickerPositionMode current calendar UI position.
+ */
+ public function getPositionMode()
+ {
+ return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
+ */
+ public function getTimeStamp()
+ {
+ if(trim($this->getText())==='')
+ return null;
+ else
+ return $this->getTimeStampFromText();
+ }
+
+ /**
+ * Sets the date for the date picker using timestamp.
+ * @param float time stamp for the date picker
+ */
+ public function setTimeStamp($value)
+ {
+ if($value===null || (is_string($value) && trim($value)===''))
+ $this->setText('');
+ else
+ {
+ $date = TPropertyValue::ensureFloat($value);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
+ $this->setText($formatter->format($date));
+ }
+ }
+
+ /**
+ * Returns the timestamp selected by the user.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getTimeStamp()}.
+ * @return integer the timestamp of the TDatePicker control.
+ * @see getTimeStamp
+ * @since 3.1.2
+ */
+ public function getData()
+ {
+ return $this->getTimeStamp();
+ }
+
+ /**
+ * Sets the timestamp represented by this control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setTimeStamp()}.
+ * @param integer the timestamp of the TDatePicker control.
+ * @see setTimeStamp
+ * @since 3.1.2
+ */
+ public function setData($value)
+ {
+ $this->setTimeStamp($value);
+ }
+
+ /**
+ * @return string the date string.
+ */
+ public function getDate()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * @param string date string
+ */
+ public function setDate($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
+ *
+ * The date picker on the client-side supports the following events.
+ * # OnDateChanged -- raised when the date is changed.
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientScript===null)
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ protected function createClientScript()
+ {
+ return new TDatePickerClientScript;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return integer the interger timestamp if valid, otherwise the original text.
+ */
+ public function getValidationPropertyValue()
+ {
+ if(($text = $this->getText()) === '')
+ return '';
+ $date = $this->getTimeStamp();
+ return $date == null ? $text : $date;
+ }
+
+ /**
+ * Publish the date picker Css asset files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getInputMode() === TDatePickerInputMode::DropDownList)
+ {
+ $page = $this->getPage();
+ $uniqueID = $this->getUniqueID();
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day');
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month');
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year');
+ }
+ $this->publishCalendarStyle();
+ $this->registerCalendarClientScriptPre();
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by adding
+ * additional date picker button if Mode is Button or ImageButton.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ {
+ parent::render($writer);
+ $this->renderDatePickerButtons($writer);
+ }
+ else
+ {
+ $this->renderDropDownListCalendar($writer);
+ if($this->hasDayPattern())
+ {
+ $this->registerCalendarClientScriptPost();
+ $this->renderDatePickerButtons($writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the date picker popup buttons.
+ */
+ protected function renderDatePickerButtons($writer)
+ {
+ if($this->getShowCalendar())
+ {
+ switch ($this->getMode())
+ {
+ case TDatePickerMode::Button:
+ $this->renderButtonDatePicker($writer);
+ break;
+ case TDatePickerMode::ImageButton :
+ $this->renderImageButtonDatePicker($writer);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Loads user input data. Override parent implementation, when InputMode
+ * is DropDownList call getDateFromPostData to get date data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ return parent::loadPostData($key, $values);
+ $value = $this->getDateFromPostData($key, $values);
+ if(!$this->getReadOnly() && $this->getText()!==$value)
+ {
+ $this->setText($value);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads date from drop down list data.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return array the date selected
+ */
+ protected function getDateFromPostData($key, $values)
+ {
+ $date = @getdate();
+
+ if(isset($values[$key.'$day']))
+ $day = intval($values[$key.'$day']);
+ else
+ $day = $date['mday'];
+
+ if(isset($values[$key.'$month']))
+ $month = intval($values[$key.'$month']) + 1;
+ else
+ $month = $date['mon'];
+
+ if(isset($values[$key.'$year']))
+ $year = intval($values[$key.'$year']);
+ else
+ $year = $date['year'];
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
+ //$date = @mktime(0, 0, 0, $month, $day, $year);
+
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
+ return $formatter->format($date);
+ }
+
+ /**
+ * Get javascript date picker options.
+ * @return array date picker client-side options
+ */
+ protected function getDatePickerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['InputMode'] = $this->getInputMode();
+ $options['Format'] = $this->getDateFormat();
+ $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
+ if(($cssClass=$this->getCssClass())!=='')
+ $options['ClassName'] = $cssClass;
+ $options['CalendarStyle'] = $this->getCalendarStyle();
+ $options['FromYear'] = $this->getFromYear();
+ $options['UpToYear'] = $this->getUpToYear();
+ switch($this->getMode())
+ {
+ case TDatePickerMode::Basic:
+ break;
+ case TDatePickerMode::Clickable:
+ $options['TriggerEvent'] = "click";
+ break;
+ default:
+ $options['Trigger'] = $this->getDatePickerButtonID();
+ break;
+ }
+ $options['PositionMode'] = $this->getPositionMode();
+
+ $options = array_merge($options, $this->getCulturalOptions());
+ if($this->_clientScript!==null)
+ $options = array_merge($options,
+ $this->_clientScript->getOptions()->toArray());
+ return $options;
+ }
+
+ /**
+ * Get javascript localization options, e.g. month and weekday names.
+ * @return array localization options.
+ */
+ protected function getCulturalOptions()
+ {
+ if($this->getCurrentCulture() == 'en')
+ return array();
+
+ $date = $this->getLocalizedCalendarInfo();
+ $options['MonthNames'] = $date->getMonthNames();
+ $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
+ $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
+
+ return $options;
+ }
+
+ /**
+ * @return string the current culture, falls back to application if culture is not set.
+ */
+ protected function getCurrentCulture()
+ {
+ $app = $this->getApplication()->getGlobalization(false);
+ return $this->getCulture() == '' ?
+ ($app ? $app->getCulture() : 'en') : $this->getCulture();
+ }
+
+ /**
+ * @return DateTimeFormatInfo date time format information for the current culture.
+ */
+ protected function getLocalizedCalendarInfo()
+ {
+ //expensive operations
+ $culture = $this->getCurrentCulture();
+ Prado::using('System.I18N.core.DateTimeFormatInfo');
+ $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
+ return $info->getDateTimeFormat();
+ }
+
+ /**
+ * Renders the drop down list date picker.
+ */
+ protected function renderDropDownListCalendar($writer)
+ {
+ if($this->getMode() == TDatePickerMode::Basic)
+ $this->setMode(TDatePickerMode::ImageButton);
+ parent::addAttributesToRender($writer);
+ $writer->removeAttribute('name');
+ $writer->removeAttribute('type');
+ $writer->addAttribute('id', $this->getClientID());
+
+ if(strlen($class = $this->getCssClass()) > 0)
+ $writer->addAttribute('class', $class);
+ $writer->renderBeginTag('span');
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getDate($this->getTimeStampFromText());
+ //$date = @getdate($this->getTimeStampFromText());
+
+ $this->renderCalendarSelections($writer, $date);
+
+ //render a hidden input field
+ $writer->addAttribute('name', $this->getUniqueID());
+ $writer->addAttribute('type', 'hidden');
+ $writer->addAttribute('value', $this->getText());
+ $writer->renderBeginTag('input');
+
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+
+ protected function hasDayPattern()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ return ($formatter->getDayPattern()!==null);
+ }
+
+ /**
+ * Renders the calendar drop down list depending on the DateFormat pattern.
+ * @param THtmlWriter the Html writer to render the drop down lists.
+ * @param array the current selected date
+ */
+ protected function renderCalendarSelections($writer, $date)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+
+ foreach($formatter->getDayMonthYearOrdering() as $type)
+ {
+ if($type == 'day')
+ $this->renderCalendarDayOptions($writer,$date['mday']);
+ elseif($type == 'month')
+ $this->renderCalendarMonthOptions($writer,$date['mon']);
+ elseif($type == 'year')
+ $this->renderCalendarYearOptions($writer,$date['year']);
+ }
+ }
+
+ /**
+ * Gets the date from the text input using TSimpleDateFormatter
+ * @return integer current selected date timestamp
+ */
+ protected function getTimeStampFromText()
+ {
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
+ return $formatter->parse($this->getText());
+ }
+
+ /**
+ * Renders a drop down lists.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param array list of selection options
+ * @param mixed selected key.
+ */
+ private function renderDropDownListOptions($writer,$options,$selected=null)
+ {
+ foreach($options as $k => $v)
+ {
+ $writer->addAttribute('value', $k);
+ if($k == $selected)
+ $writer->addAttribute('selected', 'selected');
+ $writer->renderBeginTag('option');
+ $writer->write($v);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the day drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected day.
+ */
+ protected function renderCalendarDayOptions($writer, $selected=null)
+ {
+ $days = $this->getDropDownDayOptions();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
+ $writer->addAttribute('class', 'datepicker_day_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer, $days, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return array list of day options for a drop down list.
+ */
+ protected function getDropDownDayOptions()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ $days = array();
+ $requiresPadding = $formatter->getDayPattern() === 'dd';
+ for($i=1;$i<=31;$i++)
+ {
+ $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
+ }
+ return $days;
+ }
+
+ /**
+ * Renders the month drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected month.
+ */
+ protected function renderCalendarMonthOptions($writer, $selected=null)
+ {
+ $info = $this->getLocalizedCalendarInfo();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
+ $writer->addAttribute('class', 'datepicker_month_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer,
+ $this->getLocalizedMonthNames($info), $selected-1);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Returns the localized month names that depends on the month format pattern.
+ * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
+ * and "M" return month digits.
+ * @param DateTimeFormatInfo localized date format information.
+ * @return array localized month names.
+ */
+ protected function getLocalizedMonthNames($info)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ switch($formatter->getMonthPattern())
+ {
+ case 'MMM': return $info->getAbbreviatedMonthNames();
+ case 'MM':
+ $array = array();
+ for($i=1;$i<=12;$i++)
+ $array[$i-1] = $i < 10 ? '0'.$i : $i;
+ return $array;
+ case 'M':
+ $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
+ return $array;
+ default : return $info->getMonthNames();
+ }
+ }
+
+ /**
+ * Renders the year drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected year.
+ */
+ protected function renderCalendarYearOptions($writer, $selected=null)
+ {
+ $years = array();
+ for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
+ $years[$i] = $i;
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $writer->addAttribute('class', 'datepicker_year_options');
+ $this->renderDropDownListOptions($writer, $years, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Gets the ID for the date picker trigger button.
+ * @return string unique button ID
+ */
+ protected function getDatePickerButtonID()
+ {
+ return $this->getClientID().'button';
+ }
+
+ /**
+ * Adds an additional button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderButtonDatePicker($writer)
+ {
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('type', 'button');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
+ $writer->addAttribute('value',$this->getButtonText());
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag("input");
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Adds an additional image button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderImageButtonDatePicker($writer)
+ {
+ $url = $this->getButtonImageUrl();
+ $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('src', $url);
+ $writer->addAttribute('alt', ' ');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->addAttribute('type', 'image');
+ $writer->addAttribute('onclick', 'return false;');
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @param string date picker asset file in the self::SCRIPT_PATH directory.
+ * @return string date picker asset url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the calendar style Css asset file.
+ * @return string Css file url.
+ */
+ protected function publishCalendarStyle()
+ {
+ $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * Add the client id to the input textbox, and register the client scripts.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->registerCalendarClientScriptPost();
+ }
+
+
+ /**
+ * Registers the javascript code to initialize the date picker.
+ */
+ protected function registerCalendarClientScriptPre()
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript("datepicker");
+ }
+ }
+
+ protected function registerCalendarClientScriptPost()
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
+ {
+ $spacer = $this->getAssetUrl('spacer.gif');
+ $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
+ $cs->registerEndScript('TDatePicker.spacer', $code);
+ }
+
+ $options = TJavaScript::encode($this->getDatePickerOptions());
+ $code = "new Prado.WebUI.TDatePicker($options);";
+ $cs->registerEndScript("prado:".$this->getClientID(), $code);
+ }
+ }
+}
+
+/**
+ * TDatePickerClientScript class.
+ *
+ * Client-side date picker event {@link setOnDateChanged OnDateChanged}
+ * can be modified through the {@link TDatePicker::getClientSide ClientSide}
+ * property of a date picker.
+ *
+ * The OnDateChanged event is raise when the date picker's date
+ * is changed.
+ * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
+ * as parameter to this event
+ *
+ * @author Wei Zhuo
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerClientScript extends TClientSideOptions
+{
+ /**
+ * Javascript code to execute when the date picker's date is changed.
+ * @param string javascript code
+ */
+ public function setOnDateChanged($javascript)
+ {
+ $this->setFunction('OnDateChanged', $javascript);
+ }
+
+ /**
+ * @return string javascript code to execute when the date picker's date is changed.
+ */
+ public function getOnDateChanged()
+ {
+ return $this->getOption('OnDateChanged');
+ }
+}
+
+
+/**
+ * TDatePickerInputMode class.
+ * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
+ *
+ * The following enumerable values are defined:
+ * - TextBox: text boxes are used to input date values
+ * - DropDownList: dropdown lists are used to pick up date values
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerInputMode extends TEnumerable
+{
+ const TextBox='TextBox';
+ const DropDownList='DropDownList';
+}
+
+/**
+ * TDatePickerMode class.
+ * TDatePickerMode defines the enumerable type for the possible UI mode
+ * that a {@link TDatePicker} control can take.
+ *
+ * The following enumerable values are defined:
+ * - Basic: Only shows a text input, focusing on the input shows the date picker
+ * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
+ * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
+ * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerMode extends TEnumerable
+{
+ const Basic='Basic';
+ const Clickable='Clickable';
+ const Button='Button';
+ const ImageButton='ImageButton';
+}
+
+/**
+ * TDatePickerPositionMode class.
+ * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
+ *
+ * The following enumerable values are defined:
+ * - Top: the date picker is placed above the input field
+ * - Bottom: the date picker is placed below the input field
+ *
+ * @author Carl G. Mathisen
+ * @package System.Web.UI.WebControls
+ * @since 3.1.4
+ */
+class TDatePickerPositionMode extends TEnumerable
+{
+ const Top='Top';
+ const Bottom='Bottom';
+}
diff --git a/framework/Web/UI/WebControls/TDropDownList.php b/framework/Web/UI/WebControls/TDropDownList.php
index 0eba6285..57f1f165 100644
--- a/framework/Web/UI/WebControls/TDropDownList.php
+++ b/framework/Web/UI/WebControls/TDropDownList.php
@@ -1,154 +1,154 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TDropDownList class
- *
- * TDropDownList displays a dropdown list on a Web page.
- * It inherits all properties and events from {@link TListControl}.
- *
- * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
- * a list item, set a Group attribute with it,
- *
- * $listitem->Attributes->Group="Group Name";
- * // or in template
- *
- *
- * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
- * displayed as the first list item by specifying either {@link setPromptText PromptText} or
- * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
- *
- * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
- * property is not affected by a prompt item: the items list will still be zero-based.
- *
- * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
- * available item in the dropdown list will be selected.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
-{
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('name',$this->getUniqueID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDropDownList';
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if(!$this->getEnabled(true))
- return false;
- $this->ensureDataBound();
- $selection=isset($values[$key])?$values[$key]:null;
- if($selection!==null)
- {
- $index=$this->getItems()->findIndexByValue($selection,false);
- if($this->getSelectedIndex()!==$index)
- {
- $this->setSelectedIndex($index);
- return $this->_dataChanged=true;
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndices($indices)
- {
- throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TDropDownList class
+ *
+ * TDropDownList displays a dropdown list on a Web page.
+ * It inherits all properties and events from {@link TListControl}.
+ *
+ * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
+ * a list item, set a Group attribute with it,
+ *
+ * $listitem->Attributes->Group="Group Name";
+ * // or in template
+ *
+ *
+ * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
+ * displayed as the first list item by specifying either {@link setPromptText PromptText} or
+ * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
+ *
+ * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
+ * property is not affected by a prompt item: the items list will still be zero-based.
+ *
+ * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
+ * available item in the dropdown list will be selected.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('name',$this->getUniqueID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDropDownList';
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(!$this->getEnabled(true))
+ return false;
+ $this->ensureDataBound();
+ $selection=isset($values[$key])?$values[$key]:null;
+ if($selection!==null)
+ {
+ $index=$this->getItems()->findIndexByValue($selection,false);
+ if($this->getSelectedIndex()!==$index)
+ {
+ $this->setSelectedIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/framework/Web/UI/WebControls/TDropDownListColumn.php b/framework/Web/UI/WebControls/TDropDownListColumn.php
index ffbe8f70..941a9be1 100644
--- a/framework/Web/UI/WebControls/TDropDownListColumn.php
+++ b/framework/Web/UI/WebControls/TDropDownListColumn.php
@@ -1,321 +1,321 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-Prado::using('System.Web.UI.WebControls.TDropDownList');
-
-/**
- * TDropDownListColumn class
- *
- * TDropDownListColumn represents a column that is bound to a field in a data source.
- * The cells in the column will be displayed using the data indexed by
- * {@link setDataTextField DataTextField}. You can customize the display by
- * setting {@link setDataTextFormatString DataTextFormatString}.
- *
- * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
- * with dropdown lists. Otherwise, a static text is displayed.
- * The currently selected dropndown list item is specified by the data indexed with
- * {@link setDataValueField DataValueField}.
- *
- * There are two approaches to specify the list items available for selection.
- * The first approach uses template syntax as follows,
- *
- *
- *
- *
- *
- *
- *
- * The second approach specifies a data source to be bound to the dropdown lists
- * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
- * you may also want to specify which data fields are used for item values and texts
- * by setting {@link setListValueField ListValueField} and
- * {@link setListTextField ListTextField}, respectively.
- * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
- * Note, if you specify {@link setListDataSource ListDataSource}, do it before
- * calling the datagrid's dataBind().
- *
- * The dropdown list control in the TDropDownListColumn can be accessed by one of
- * the following two methods:
- *
- * $datagridItem->DropDownListColumnID->DropDownList
- * $datagridItem->DropDownListColumnID->Controls[0]
- *
- * The second method is possible because the dropdown list control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDropDownListColumn extends TDataGridColumn
-{
- private $_stateLoaded=false;
- private $_dataBound=false;
- private $_listControl=null;
-
- public function __construct()
- {
- $this->_listControl=new TDropDownList;
- }
-
- /**
- * Loads items from viewstate.
- * This method overrides the parent implementation by loading list items
- * @param mixed state values
- */
- public function loadState($state)
- {
- parent::loadState($state);
- $this->_stateLoaded=true;
- if(!$this->_dataBound)
- $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
- }
-
- /**
- * Saves items into viewstate.
- * This method overrides the parent implementation by saving list items
- */
- public function saveState()
- {
- $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
- return parent::saveState();
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- // Do not add items from template if items are loaded from viewstate
- if(!$this->_stateLoaded && ($object instanceof TListItem))
- {
- $object->setSelected(false);
- $index=$this->_listControl->getItems()->add($object);
- }
- }
-
- /**
- * @return string the field of the data source that provides the text content of the column.
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * Sets the field of the data source that provides the text content of the column.
- * If this is not set, the data specified via {@link getDataValueField DataValueField}
- * will be displayed in the column.
- * @param string the field of the data source that provides the text content of the column.
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function getDataValueField()
- {
- return $this->getViewState('DataValueField','');
- }
-
- /**
- * Sets the field of the data source that provides the key selecting an item in dropdown list.
- * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
- * applying the formatting string) will be used for selection, instead.
- * @param string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function setDataValueField($value)
- {
- $this->setViewState('DataValueField',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return Traversable data source to be bound to the dropdown list boxes.
- */
- public function getListDataSource()
- {
- return $this->_listControl->getDataSource();
- }
-
- /**
- * @param Traversable|array|string data source to be bound to the dropdown list boxes.
- */
- public function setListDataSource($value)
- {
- $this->_listControl->setDataSource($value);
- }
-
- /**
- * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
- */
- public function getListValueField()
- {
- return $this->getViewState('ListValueField','');
- }
-
- /**
- * @param string the data field used to populate the values of the dropdown list items
- */
- public function setListValueField($value)
- {
- $this->setViewState('ListValueField',$value,'');
- }
-
- /**
- * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
- */
- public function getListTextField()
- {
- return $this->getViewState('ListTextField','');
- }
-
- /**
- * @param string the data field used to populate the texts of the dropdown list items
- */
- public function setListTextField($value)
- {
- $this->setViewState('ListTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the list item texts will be displayed.
- */
- public function getListTextFormatString()
- {
- return $this->getViewState('ListTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the list item texts will be displayed.
- */
- public function setListTextFormatString($value)
- {
- $this->setViewState('ListTextFormatString',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a textbox for item in edit mode and the column is not read-only.
- * Otherwise it displays a static text.
- * The caption of the button and the static text are retrieved
- * from the datasource.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
- {
- $this->_listControl->setDataTextField($this->getListTextField());
- $this->_listControl->setDataValueField($this->getListValueField());
- $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
- $this->_listControl->dataBind();
- $this->_dataBound=true;
- }
- switch($itemType)
- {
- case TListItemType::EditItem:
- if(!$this->getReadOnly())
- {
- $listControl=clone $this->_listControl;
- $cell->getControls()->add($listControl);
- $cell->registerObject('DropDownList',$listControl);
- $control=$listControl;
- }
- else
- $control=$cell;
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
- $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- default:
- parent::initializeCell($cell,$columnIndex,$itemType);
- break;
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($valueField=$this->getDataValueField())!=='')
- $value=$this->getDataFieldValue($data,$valueField);
- else
- $value='';
- if(($textField=$this->getDataTextField())!=='')
- {
- $text=$this->getDataFieldValue($data,$textField);
- if($valueField==='')
- $value=$text;
- $formatString=$this->getDataTextFormatString();
- $text=$this->formatDataValue($formatString,$text);
- }
- else
- $text=$value;
- if($sender instanceof TTableCell)
- $sender->setText($text);
- else if($sender instanceof TDropDownList)
- $sender->setSelectedValue($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+Prado::using('System.Web.UI.WebControls.TDropDownList');
+
+/**
+ * TDropDownListColumn class
+ *
+ * TDropDownListColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataTextField DataTextField}. You can customize the display by
+ * setting {@link setDataTextFormatString DataTextFormatString}.
+ *
+ * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
+ * with dropdown lists. Otherwise, a static text is displayed.
+ * The currently selected dropndown list item is specified by the data indexed with
+ * {@link setDataValueField DataValueField}.
+ *
+ * There are two approaches to specify the list items available for selection.
+ * The first approach uses template syntax as follows,
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * The second approach specifies a data source to be bound to the dropdown lists
+ * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
+ * you may also want to specify which data fields are used for item values and texts
+ * by setting {@link setListValueField ListValueField} and
+ * {@link setListTextField ListTextField}, respectively.
+ * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
+ * Note, if you specify {@link setListDataSource ListDataSource}, do it before
+ * calling the datagrid's dataBind().
+ *
+ * The dropdown list control in the TDropDownListColumn can be accessed by one of
+ * the following two methods:
+ *
+ * $datagridItem->DropDownListColumnID->DropDownList
+ * $datagridItem->DropDownListColumnID->Controls[0]
+ *
+ * The second method is possible because the dropdown list control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDropDownListColumn extends TDataGridColumn
+{
+ private $_stateLoaded=false;
+ private $_dataBound=false;
+ private $_listControl=null;
+
+ public function __construct()
+ {
+ $this->_listControl=new TDropDownList;
+ }
+
+ /**
+ * Loads items from viewstate.
+ * This method overrides the parent implementation by loading list items
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ parent::loadState($state);
+ $this->_stateLoaded=true;
+ if(!$this->_dataBound)
+ $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
+ }
+
+ /**
+ * Saves items into viewstate.
+ * This method overrides the parent implementation by saving list items
+ */
+ public function saveState()
+ {
+ $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
+ return parent::saveState();
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ // Do not add items from template if items are loaded from viewstate
+ if(!$this->_stateLoaded && ($object instanceof TListItem))
+ {
+ $object->setSelected(false);
+ $index=$this->_listControl->getItems()->add($object);
+ }
+ }
+
+ /**
+ * @return string the field of the data source that provides the text content of the column.
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the text content of the column.
+ * If this is not set, the data specified via {@link getDataValueField DataValueField}
+ * will be displayed in the column.
+ * @param string the field of the data source that provides the text content of the column.
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function getDataValueField()
+ {
+ return $this->getViewState('DataValueField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the key selecting an item in dropdown list.
+ * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
+ * applying the formatting string) will be used for selection, instead.
+ * @param string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function setDataValueField($value)
+ {
+ $this->setViewState('DataValueField',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return Traversable data source to be bound to the dropdown list boxes.
+ */
+ public function getListDataSource()
+ {
+ return $this->_listControl->getDataSource();
+ }
+
+ /**
+ * @param Traversable|array|string data source to be bound to the dropdown list boxes.
+ */
+ public function setListDataSource($value)
+ {
+ $this->_listControl->setDataSource($value);
+ }
+
+ /**
+ * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
+ */
+ public function getListValueField()
+ {
+ return $this->getViewState('ListValueField','');
+ }
+
+ /**
+ * @param string the data field used to populate the values of the dropdown list items
+ */
+ public function setListValueField($value)
+ {
+ $this->setViewState('ListValueField',$value,'');
+ }
+
+ /**
+ * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
+ */
+ public function getListTextField()
+ {
+ return $this->getViewState('ListTextField','');
+ }
+
+ /**
+ * @param string the data field used to populate the texts of the dropdown list items
+ */
+ public function setListTextField($value)
+ {
+ $this->setViewState('ListTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function getListTextFormatString()
+ {
+ return $this->getViewState('ListTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function setListTextFormatString($value)
+ {
+ $this->setViewState('ListTextFormatString',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a textbox for item in edit mode and the column is not read-only.
+ * Otherwise it displays a static text.
+ * The caption of the button and the static text are retrieved
+ * from the datasource.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
+ {
+ $this->_listControl->setDataTextField($this->getListTextField());
+ $this->_listControl->setDataValueField($this->getListValueField());
+ $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
+ $this->_listControl->dataBind();
+ $this->_dataBound=true;
+ }
+ switch($itemType)
+ {
+ case TListItemType::EditItem:
+ if(!$this->getReadOnly())
+ {
+ $listControl=clone $this->_listControl;
+ $cell->getControls()->add($listControl);
+ $cell->registerObject('DropDownList',$listControl);
+ $control=$listControl;
+ }
+ else
+ $control=$cell;
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ default:
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ break;
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($valueField=$this->getDataValueField())!=='')
+ $value=$this->getDataFieldValue($data,$valueField);
+ else
+ $value='';
+ if(($textField=$this->getDataTextField())!=='')
+ {
+ $text=$this->getDataFieldValue($data,$textField);
+ if($valueField==='')
+ $value=$text;
+ $formatString=$this->getDataTextFormatString();
+ $text=$this->formatDataValue($formatString,$text);
+ }
+ else
+ $text=$value;
+ if($sender instanceof TTableCell)
+ $sender->setText($text);
+ else if($sender instanceof TDropDownList)
+ $sender->setSelectedValue($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TEditCommandColumn.php b/framework/Web/UI/WebControls/TEditCommandColumn.php
index 44004807..b10c6880 100644
--- a/framework/Web/UI/WebControls/TEditCommandColumn.php
+++ b/framework/Web/UI/WebControls/TEditCommandColumn.php
@@ -1,265 +1,265 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TEditCommandColumn class
- *
- * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
- *
- * TEditCommandColumn will create an edit button if a cell is not in edit mode.
- * Otherwise an update button and a cancel button will be created within the cell.
- * The button captions are specified using {@link setEditText EditText},
- * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
- *
- * The buttons in the column can be set to display as hyperlinks, push or image buttons
- * by setting the {@link setButtonType ButtonType} property.
- *
- * When an edit button is clicked, the datagrid will generate an
- * {@link onEditCommand OnEditCommand} event. When an update/cancel button
- * is clicked, the datagrid will generate an
- * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
- * You can write these event handlers to change the state of specific datagrid item.
- *
- * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
- * properties affect the corresponding properties of the edit and update buttons.
- * The cancel button does not cause validation by default.
- *
- * The command buttons in the column can be accessed by one of the following methods:
- *
- * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
- * $datagridItem->ButtonColumnID->Controls[0]
- *
- * The second method is possible because the button control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEditCommandColumn extends TDataGridColumn
-{
- /**
- * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
- }
-
- /**
- * @param TButtonColumnType the type of command button.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
- }
-
- /**
- * @return string the caption of the edit button. Defaults to 'Edit'.
- */
- public function getEditText()
- {
- return $this->getViewState('EditText','Edit');
- }
-
- /**
- * @param string the caption of the edit button
- */
- public function setEditText($value)
- {
- $this->setViewState('EditText',$value,'Edit');
- }
-
- /**
- * @return string the URL of the image file for edit image buttons
- */
- public function getEditImageUrl()
- {
- return $this->getViewState('EditImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for edit image buttons
- */
- public function setEditImageUrl($value)
- {
- $this->setViewState('EditImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the update button. Defaults to 'Update'.
- */
- public function getUpdateText()
- {
- return $this->getViewState('UpdateText','Update');
- }
-
- /**
- * @param string the caption of the update button
- */
- public function setUpdateText($value)
- {
- $this->setViewState('UpdateText',$value,'Update');
- }
-
- /**
- * @return string the URL of the image file for update image buttons
- */
- public function getUpdateImageUrl()
- {
- return $this->getViewState('UpdateImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for update image buttons
- */
- public function setUpdateImageUrl($value)
- {
- $this->setViewState('UpdateImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the cancel button. Defaults to 'Cancel'.
- */
- public function getCancelText()
- {
- return $this->getViewState('CancelText','Cancel');
- }
-
- /**
- * @param string the caption of the cancel button
- */
- public function setCancelText($value)
- {
- $this->setViewState('CancelText',$value,'Cancel');
- }
-
- /**
- * @return string the URL of the image file for cancel image buttons
- */
- public function getCancelImageUrl()
- {
- return $this->getViewState('CancelImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for cancel image buttons
- */
- public function setCancelImageUrl($value)
- {
- $this->setViewState('CancelImageUrl',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by edit or update button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the edit or update button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the edit or update button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates an update and a cancel button for cell in edit mode.
- * Otherwise it creates an edit button.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- $button=$this->createButton('Edit',$this->getEditText(),false,'');
- $cell->getControls()->add($button);
- $cell->registerObject('EditButton',$button);
- }
- else if($itemType===TListItemType::EditItem)
- {
- $controls=$cell->getControls();
- $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
- $controls->add($button);
- $cell->registerObject('UpdateButton',$button);
- $controls->add(' ');
- $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
- $controls->add($button);
- $cell->registerObject('CancelButton',$button);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Creates a button and initializes its properties.
- * The button type is determined by {@link getButtonType ButtonType}.
- * @param string command name associated with the button
- * @param string button caption
- * @param boolean whether the button should cause validation
- * @param string the validation group that the button belongs to
- * @return mixed the newly created button.
- */
- protected function createButton($commandName,$text,$causesValidation,$validationGroup)
- {
- if($this->getButtonType()===TButtonColumnType::LinkButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- else if($this->getButtonType()===TButtonColumnType::PushButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
- else // image buttons
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- if(strcasecmp($commandName,'Update')===0)
- $url=$this->getUpdateImageUrl();
- else if(strcasecmp($commandName,'Cancel')===0)
- $url=$this->getCancelImageUrl();
- else
- $url=$this->getEditImageUrl();
- $button->setImageUrl($url);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCausesValidation($causesValidation);
- $button->setValidationGroup($validationGroup);
- return $button;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TEditCommandColumn class
+ *
+ * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
+ *
+ * TEditCommandColumn will create an edit button if a cell is not in edit mode.
+ * Otherwise an update button and a cancel button will be created within the cell.
+ * The button captions are specified using {@link setEditText EditText},
+ * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
+ *
+ * The buttons in the column can be set to display as hyperlinks, push or image buttons
+ * by setting the {@link setButtonType ButtonType} property.
+ *
+ * When an edit button is clicked, the datagrid will generate an
+ * {@link onEditCommand OnEditCommand} event. When an update/cancel button
+ * is clicked, the datagrid will generate an
+ * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
+ * You can write these event handlers to change the state of specific datagrid item.
+ *
+ * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
+ * properties affect the corresponding properties of the edit and update buttons.
+ * The cancel button does not cause validation by default.
+ *
+ * The command buttons in the column can be accessed by one of the following methods:
+ *
+ * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
+ * $datagridItem->ButtonColumnID->Controls[0]
+ *
+ * The second method is possible because the button control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEditCommandColumn extends TDataGridColumn
+{
+ /**
+ * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @param TButtonColumnType the type of command button.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @return string the caption of the edit button. Defaults to 'Edit'.
+ */
+ public function getEditText()
+ {
+ return $this->getViewState('EditText','Edit');
+ }
+
+ /**
+ * @param string the caption of the edit button
+ */
+ public function setEditText($value)
+ {
+ $this->setViewState('EditText',$value,'Edit');
+ }
+
+ /**
+ * @return string the URL of the image file for edit image buttons
+ */
+ public function getEditImageUrl()
+ {
+ return $this->getViewState('EditImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for edit image buttons
+ */
+ public function setEditImageUrl($value)
+ {
+ $this->setViewState('EditImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the update button. Defaults to 'Update'.
+ */
+ public function getUpdateText()
+ {
+ return $this->getViewState('UpdateText','Update');
+ }
+
+ /**
+ * @param string the caption of the update button
+ */
+ public function setUpdateText($value)
+ {
+ $this->setViewState('UpdateText',$value,'Update');
+ }
+
+ /**
+ * @return string the URL of the image file for update image buttons
+ */
+ public function getUpdateImageUrl()
+ {
+ return $this->getViewState('UpdateImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for update image buttons
+ */
+ public function setUpdateImageUrl($value)
+ {
+ $this->setViewState('UpdateImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the cancel button. Defaults to 'Cancel'.
+ */
+ public function getCancelText()
+ {
+ return $this->getViewState('CancelText','Cancel');
+ }
+
+ /**
+ * @param string the caption of the cancel button
+ */
+ public function setCancelText($value)
+ {
+ $this->setViewState('CancelText',$value,'Cancel');
+ }
+
+ /**
+ * @return string the URL of the image file for cancel image buttons
+ */
+ public function getCancelImageUrl()
+ {
+ return $this->getViewState('CancelImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for cancel image buttons
+ */
+ public function setCancelImageUrl($value)
+ {
+ $this->setViewState('CancelImageUrl',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by edit or update button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates an update and a cancel button for cell in edit mode.
+ * Otherwise it creates an edit button.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ $button=$this->createButton('Edit',$this->getEditText(),false,'');
+ $cell->getControls()->add($button);
+ $cell->registerObject('EditButton',$button);
+ }
+ else if($itemType===TListItemType::EditItem)
+ {
+ $controls=$cell->getControls();
+ $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
+ $controls->add($button);
+ $cell->registerObject('UpdateButton',$button);
+ $controls->add(' ');
+ $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
+ $controls->add($button);
+ $cell->registerObject('CancelButton',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Creates a button and initializes its properties.
+ * The button type is determined by {@link getButtonType ButtonType}.
+ * @param string command name associated with the button
+ * @param string button caption
+ * @param boolean whether the button should cause validation
+ * @param string the validation group that the button belongs to
+ * @return mixed the newly created button.
+ */
+ protected function createButton($commandName,$text,$causesValidation,$validationGroup)
+ {
+ if($this->getButtonType()===TButtonColumnType::LinkButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ else if($this->getButtonType()===TButtonColumnType::PushButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
+ else // image buttons
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ if(strcasecmp($commandName,'Update')===0)
+ $url=$this->getUpdateImageUrl();
+ else if(strcasecmp($commandName,'Cancel')===0)
+ $url=$this->getCancelImageUrl();
+ else
+ $url=$this->getEditImageUrl();
+ $button->setImageUrl($url);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCausesValidation($causesValidation);
+ $button->setValidationGroup($validationGroup);
+ return $button;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TEmailAddressValidator.php b/framework/Web/UI/WebControls/TEmailAddressValidator.php
index a198ffc4..b0b51208 100644
--- a/framework/Web/UI/WebControls/TEmailAddressValidator.php
+++ b/framework/Web/UI/WebControls/TEmailAddressValidator.php
@@ -1,97 +1,97 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TRegularExpressionValidator class
- */
-Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
-
-/**
- * TEmailAddressValidator class
- *
- * TEmailAddressValidator validates whether the value of an associated
- * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
- * is true, it will check MX record for the email adress, provided
- * checkdnsrr() is available in the installed PHP.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEmailAddressValidator extends TRegularExpressionValidator
-{
- /**
- * Regular expression used to validate the email address
- */
- const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
-
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEmailAddressValidator';
- }
-
- /**
- * @return string the regular expression that determines the pattern used to validate a field.
- */
- public function getRegularExpression()
- {
- $regex=parent::getRegularExpression();
- return $regex===''?self::EMAIL_REGEXP:$regex;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- public function evaluateIsValid()
- {
- $valid=parent::evaluateIsValid();
- if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))!=='')
- {
- if(($pos=strpos($value,'@'))!==false)
- {
- $domain=substr($value,$pos+1);
- return $domain===''?false:checkdnsrr($domain,'MX');
- }
- else
- return false;
- }
- }
- return $valid;
- }
-
- /**
- * @return boolean whether to check MX record for the email address being validated. Defaults to true.
- */
- public function getCheckMXRecord()
- {
- return $this->getViewState('CheckMXRecord',true);
- }
-
- /**
- * @param boolean whether to check MX record for the email address being validated.
- * Note, if {@link checkdnsrr} is not available, this check will not be performed.
- */
- public function setCheckMXRecord($value)
- {
- $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TRegularExpressionValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
+
+/**
+ * TEmailAddressValidator class
+ *
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
+ * is true, it will check MX record for the email adress, provided
+ * checkdnsrr() is available in the installed PHP.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEmailAddressValidator extends TRegularExpressionValidator
+{
+ /**
+ * Regular expression used to validate the email address
+ */
+ const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEmailAddressValidator';
+ }
+
+ /**
+ * @return string the regular expression that determines the pattern used to validate a field.
+ */
+ public function getRegularExpression()
+ {
+ $regex=parent::getRegularExpression();
+ return $regex===''?self::EMAIL_REGEXP:$regex;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ public function evaluateIsValid()
+ {
+ $valid=parent::evaluateIsValid();
+ if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))!=='')
+ {
+ if(($pos=strpos($value,'@'))!==false)
+ {
+ $domain=substr($value,$pos+1);
+ return $domain===''?false:checkdnsrr($domain,'MX');
+ }
+ else
+ return false;
+ }
+ }
+ return $valid;
+ }
+
+ /**
+ * @return boolean whether to check MX record for the email address being validated. Defaults to true.
+ */
+ public function getCheckMXRecord()
+ {
+ return $this->getViewState('CheckMXRecord',true);
+ }
+
+ /**
+ * @param boolean whether to check MX record for the email address being validated.
+ * Note, if {@link checkdnsrr} is not available, this check will not be performed.
+ */
+ public function setCheckMXRecord($value)
+ {
+ $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TExpression.php b/framework/Web/UI/WebControls/TExpression.php
index 9b8eb7e7..cf38df70 100644
--- a/framework/Web/UI/WebControls/TExpression.php
+++ b/framework/Web/UI/WebControls/TExpression.php
@@ -1,62 +1,62 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TExpression class
- *
- * TExpression evaluates a PHP expression and renders the result.
- * The expression is evaluated during the rendering stage. The expression being
- * evaluated can be set via the property {@link setExpression Expression}.
- * The context of the expression evaluated is the TExpression object itself.
- *
- * Note, since TExpression allows evaluation of arbitrary PHP expression,
- * make sure {@link setExpression Expression} does not come directly from user input.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TExpression extends TControl
-{
- /**
- * @var string PHP expression to be evaluated
- */
- private $_e='';
-
- /**
- * @return string the expression to be evaluated
- */
- public function getExpression()
- {
- return $this->_e;
- }
-
- /**
- * @param string the expression to be evaluated
- */
- public function setExpression($value)
- {
- $this->_e=$value;
- }
-
- /**
- * Renders the evaluation result of the expression.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_e!=='')
- $writer->write($this->evaluateExpression($this->_e));
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TExpression class
+ *
+ * TExpression evaluates a PHP expression and renders the result.
+ * The expression is evaluated during the rendering stage. The expression being
+ * evaluated can be set via the property {@link setExpression Expression}.
+ * The context of the expression evaluated is the TExpression object itself.
+ *
+ * Note, since TExpression allows evaluation of arbitrary PHP expression,
+ * make sure {@link setExpression Expression} does not come directly from user input.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TExpression extends TControl
+{
+ /**
+ * @var string PHP expression to be evaluated
+ */
+ private $_e='';
+
+ /**
+ * @return string the expression to be evaluated
+ */
+ public function getExpression()
+ {
+ return $this->_e;
+ }
+
+ /**
+ * @param string the expression to be evaluated
+ */
+ public function setExpression($value)
+ {
+ $this->_e=$value;
+ }
+
+ /**
+ * Renders the evaluation result of the expression.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_e!=='')
+ $writer->write($this->evaluateExpression($this->_e));
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TFileUpload.php b/framework/Web/UI/WebControls/TFileUpload.php
index 0f7d226d..051e3e0b 100644
--- a/framework/Web/UI/WebControls/TFileUpload.php
+++ b/framework/Web/UI/WebControls/TFileUpload.php
@@ -1,281 +1,281 @@
-, Qiang Xue
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFileUpload class
- *
- * TFileUpload displays a file upload field on a page. Upon postback,
- * the text entered into the field will be treated as the name of the file
- * that will be uploaded to the server. The property {@link getHasFile HasFile}
- * indicates whether the file upload is successful. If successful, the file
- * may be obtained by calling {@link saveAs} to save it at a specified place.
- * You can use {@link getFileName FileName}, {@link getFileType FileType},
- * {@link getFileSize FileSize} to get the original client-side file name,
- * the file mime type, and the file size information. If the upload is not
- * successful, {@link getErrorCode ErrorCode} contains the error code
- * describing the cause of failure.
- *
- * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
- * (whether it succeeds or not).
- *
- * @author Marcus Nyeholt , Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
-{
- /**
- * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
- */
- const MAX_FILE_SIZE=1048576;
- /**
- * @var integer the size of the uploaded file (in bytes)
- */
- private $_fileSize=0;
- /**
- * @var string The original name of the file on the client machine
- */
- private $_fileName='';
- /**
- * @var string the name of the temporary file storing the uploaded file
- */
- private $_localName='';
- /**
- * @var string the uploaded file mime type
- */
- private $_fileType='';
- /**
- * @var integer error code of the current file upload
- */
- protected $_errorCode=UPLOAD_ERR_NO_FILE;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * @return string tag name of the file upload control
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets name attribute to the unique ID of the control.
- * This method overrides the parent implementation with additional file update control specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $this->getPage()->ensureRenderInForm($this);
- parent::addAttributesToRender($writer);
- $writer->addAttribute('type','file');
- $writer->addAttribute('name',$this->getUniqueID());
- $isEnabled=$this->getEnabled(true);
- if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Sets Enctype of the form on the page.
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if(($form=$this->getPage()->getForm())!==null)
- $form->setEnctype('multipart/form-data');
- $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
- * @see setMaxFileSize
- */
- public function getMaxFileSize()
- {
- return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
- }
-
- /**
- * Sets the maximum size that a file can be uploaded.
- * Note, this is an advisory value to the browser. Sets this property with
- * a reasonably large size to save users the trouble of waiting
- * for a big file being transferred only to find that it was too big
- * and the transfer failed.
- * @param int the maximum upload size allowed for a file.
- */
- public function setMaxFileSize($size)
- {
- $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
- }
-
- /**
- * @return string the original full path name of the file on the client machine
- */
- public function getFileName()
- {
- return $this->_fileName;
- }
-
- /**
- * @return integer the actual size of the uploaded file in bytes
- */
- public function getFileSize()
- {
- return $this->_fileSize;
- }
-
- /**
- * @return string the MIME-type of the uploaded file (such as "image/gif").
- * This mime type is not checked on the server side and do not take its value for granted.
- */
- public function getFileType()
- {
- return $this->_fileType;
- }
-
- /**
- * @return string the local name of the file (where it is after being uploaded).
- * Note, PHP will delete this file automatically after finishing this round of request.
- */
- public function getLocalName()
- {
- return $this->_localName;
- }
-
- /**
- * Returns an error code describing the status of this file uploading.
- * @return integer the error code
- * @see http://www.php.net/manual/en/features.file-upload.errors.php
- */
- public function getErrorCode()
- {
- return $this->_errorCode;
- }
-
- /**
- * @return boolean whether the file is uploaded successfully
- */
- public function getHasFile()
- {
- return $this->_errorCode===UPLOAD_ERR_OK;
- }
-
- /**
- * Saves the uploaded file.
- * @param string the file name used to save the uploaded file
- * @param boolean whether to delete the temporary file after saving.
- * If true, you will not be able to save the uploaded file again.
- * @return boolean true if the file saving is successful
- */
- public function saveAs($fileName,$deleteTempFile=true)
- {
- if($this->_errorCode===UPLOAD_ERR_OK)
- {
- if($deleteTempFile)
- return move_uploaded_file($this->_localName,$fileName);
- else if(is_uploaded_file($this->_localName))
- return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
- else
- return false;
- }
- else
- return false;
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if(isset($_FILES[$key]))
- {
- $this->_fileName=$_FILES[$key]['name'];
- $this->_fileSize=$_FILES[$key]['size'];
- $this->_fileType=$_FILES[$key]['type'];
- $this->_errorCode=$_FILES[$key]['error'];
- $this->_localName=$_FILES[$key]['tmp_name'];
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method calls {@link onFileUpload} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onFileUpload(null);
- }
-
- /**
- * This method is invoked when a file is uploaded during a postback.
- * The method raises OnFileUpload event to fire up the event handler.
- * If you override this method, be sure to call the parent implementation
- * so that the event delegates can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onFileUpload($param)
- {
- $this->raiseEvent('OnFileUpload',$this,$param);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the original file name as the property value to be validated.
- * This method is required by IValidatable property.
- * @return mixed the property value to be validated
- */
- public function getValidationPropertyValue()
- {
- return $this->getFileName();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
-}
-
+, Qiang Xue
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFileUpload class
+ *
+ * TFileUpload displays a file upload field on a page. Upon postback,
+ * the text entered into the field will be treated as the name of the file
+ * that will be uploaded to the server. The property {@link getHasFile HasFile}
+ * indicates whether the file upload is successful. If successful, the file
+ * may be obtained by calling {@link saveAs} to save it at a specified place.
+ * You can use {@link getFileName FileName}, {@link getFileType FileType},
+ * {@link getFileSize FileSize} to get the original client-side file name,
+ * the file mime type, and the file size information. If the upload is not
+ * successful, {@link getErrorCode ErrorCode} contains the error code
+ * describing the cause of failure.
+ *
+ * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
+ * (whether it succeeds or not).
+ *
+ * @author Marcus Nyeholt , Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
+{
+ /**
+ * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
+ */
+ const MAX_FILE_SIZE=1048576;
+ /**
+ * @var integer the size of the uploaded file (in bytes)
+ */
+ private $_fileSize=0;
+ /**
+ * @var string The original name of the file on the client machine
+ */
+ private $_fileName='';
+ /**
+ * @var string the name of the temporary file storing the uploaded file
+ */
+ private $_localName='';
+ /**
+ * @var string the uploaded file mime type
+ */
+ private $_fileType='';
+ /**
+ * @var integer error code of the current file upload
+ */
+ protected $_errorCode=UPLOAD_ERR_NO_FILE;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the file upload control
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets name attribute to the unique ID of the control.
+ * This method overrides the parent implementation with additional file update control specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $this->getPage()->ensureRenderInForm($this);
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('type','file');
+ $writer->addAttribute('name',$this->getUniqueID());
+ $isEnabled=$this->getEnabled(true);
+ if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Sets Enctype of the form on the page.
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if(($form=$this->getPage()->getForm())!==null)
+ $form->setEnctype('multipart/form-data');
+ $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
+ * @see setMaxFileSize
+ */
+ public function getMaxFileSize()
+ {
+ return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * Sets the maximum size that a file can be uploaded.
+ * Note, this is an advisory value to the browser. Sets this property with
+ * a reasonably large size to save users the trouble of waiting
+ * for a big file being transferred only to find that it was too big
+ * and the transfer failed.
+ * @param int the maximum upload size allowed for a file.
+ */
+ public function setMaxFileSize($size)
+ {
+ $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * @return string the original full path name of the file on the client machine
+ */
+ public function getFileName()
+ {
+ return $this->_fileName;
+ }
+
+ /**
+ * @return integer the actual size of the uploaded file in bytes
+ */
+ public function getFileSize()
+ {
+ return $this->_fileSize;
+ }
+
+ /**
+ * @return string the MIME-type of the uploaded file (such as "image/gif").
+ * This mime type is not checked on the server side and do not take its value for granted.
+ */
+ public function getFileType()
+ {
+ return $this->_fileType;
+ }
+
+ /**
+ * @return string the local name of the file (where it is after being uploaded).
+ * Note, PHP will delete this file automatically after finishing this round of request.
+ */
+ public function getLocalName()
+ {
+ return $this->_localName;
+ }
+
+ /**
+ * Returns an error code describing the status of this file uploading.
+ * @return integer the error code
+ * @see http://www.php.net/manual/en/features.file-upload.errors.php
+ */
+ public function getErrorCode()
+ {
+ return $this->_errorCode;
+ }
+
+ /**
+ * @return boolean whether the file is uploaded successfully
+ */
+ public function getHasFile()
+ {
+ return $this->_errorCode===UPLOAD_ERR_OK;
+ }
+
+ /**
+ * Saves the uploaded file.
+ * @param string the file name used to save the uploaded file
+ * @param boolean whether to delete the temporary file after saving.
+ * If true, you will not be able to save the uploaded file again.
+ * @return boolean true if the file saving is successful
+ */
+ public function saveAs($fileName,$deleteTempFile=true)
+ {
+ if($this->_errorCode===UPLOAD_ERR_OK)
+ {
+ if($deleteTempFile)
+ return move_uploaded_file($this->_localName,$fileName);
+ else if(is_uploaded_file($this->_localName))
+ return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(isset($_FILES[$key]))
+ {
+ $this->_fileName=$_FILES[$key]['name'];
+ $this->_fileSize=$_FILES[$key]['size'];
+ $this->_fileType=$_FILES[$key]['type'];
+ $this->_errorCode=$_FILES[$key]['error'];
+ $this->_localName=$_FILES[$key]['tmp_name'];
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onFileUpload} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onFileUpload(null);
+ }
+
+ /**
+ * This method is invoked when a file is uploaded during a postback.
+ * The method raises OnFileUpload event to fire up the event handler.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event delegates can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onFileUpload($param)
+ {
+ $this->raiseEvent('OnFileUpload',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the original file name as the property value to be validated.
+ * This method is required by IValidatable property.
+ * @return mixed the property value to be validated
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getFileName();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+}
+
diff --git a/framework/Web/UI/WebControls/TFlushOutput.php b/framework/Web/UI/WebControls/TFlushOutput.php
index cc55646d..0ea9b389 100644
--- a/framework/Web/UI/WebControls/TFlushOutput.php
+++ b/framework/Web/UI/WebControls/TFlushOutput.php
@@ -1,86 +1,86 @@
-
- * @link http://www.pradosoft.com/
- * @license http://www.pradosoft.com/license/
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFlushOutput class.
- *
- * TFlushOutput enables forced flushing of the current output buffer
- * at (a) certain point(s) in the page, after rendering of all previous
- * controls has been completed.
- *
- * To use TFlushOutput, simply place it in a template where you want
- * the have the output buffered between the start of the page or the
- * last TFlushOutput to be sent to the client immediately
- *
- *
- *
- *
- * You can specify whether you want to keep buffering of the output
- * (if it was enabled) till the next occourence of a
- * or the end of the page rendering, or stop buffering, by using the
- * {@link setContinueBuffering ContinueBuffering}.
- *
- * @author Berczi Gabor
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TFlushOutput extends TControl
-{
- /**
- * @var boolean whether to continue buffering of output
- */
- private $_continueBuffering=true;
-
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->EnableViewState = false;
- }
-
- /**
- * @return Tells whether buffering of output can continue after this point
- */
- public function getContinueBuffering()
- {
- return $this->_continueBuffering;
- }
-
- /**
- * @param boolean sets whether buffering of output can continue after this point
- */
- public function setContinueBuffering($value)
- {
- $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Flushes the output of all completely rendered controls to the client.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
-//$writer->write('');
- // ajax responses can't be parsed by the client side before loaded and returned completely,
- // so don't bother with flushing output somewhere mid-page if refreshing in a callback
- if (!$this->Page->IsCallback)
- {
- $this->Page->flushWriter();
-// $this->Application->flushOutput($this->ContinueBuffering);
- }
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TFlushOutput.php $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFlushOutput class.
+ *
+ * TFlushOutput enables forced flushing of the current output buffer
+ * at (a) certain point(s) in the page, after rendering of all previous
+ * controls has been completed.
+ *
+ * To use TFlushOutput, simply place it in a template where you want
+ * the have the output buffered between the start of the page or the
+ * last TFlushOutput to be sent to the client immediately
+ *
+ *
+ *
+ *
+ * You can specify whether you want to keep buffering of the output
+ * (if it was enabled) till the next occourence of a
+ * or the end of the page rendering, or stop buffering, by using the
+ * {@link setContinueBuffering ContinueBuffering}.
+ *
+ * @author Berczi Gabor
+ * @version $Id: TFlushOutput.php $
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TFlushOutput extends TControl
+{
+ /**
+ * @var boolean whether to continue buffering of output
+ */
+ private $_continueBuffering=true;
+
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->EnableViewState = false;
+ }
+
+ /**
+ * @return Tells whether buffering of output can continue after this point
+ */
+ public function getContinueBuffering()
+ {
+ return $this->_continueBuffering;
+ }
+
+ /**
+ * @param boolean sets whether buffering of output can continue after this point
+ */
+ public function setContinueBuffering($value)
+ {
+ $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Flushes the output of all completely rendered controls to the client.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+//$writer->write('');
+ // ajax responses can't be parsed by the client side before loaded and returned completely,
+ // so don't bother with flushing output somewhere mid-page if refreshing in a callback
+ if (!$this->Page->IsCallback)
+ {
+ $this->Page->flushWriter();
+// $this->Application->flushOutput($this->ContinueBuffering);
+ }
+ }
+}
+
?>
\ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TFont.php b/framework/Web/UI/WebControls/TFont.php
index 4da42508..771b6a4e 100644
--- a/framework/Web/UI/WebControls/TFont.php
+++ b/framework/Web/UI/WebControls/TFont.php
@@ -1,318 +1,318 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFont class
- *
- * TFont encapsulates the CSS style fields related with font settings.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFont extends TComponent
-{
- /**
- * Bits indicating the font states.
- */
- const IS_BOLD=0x01;
- const IS_ITALIC=0x02;
- const IS_OVERLINE=0x04;
- const IS_STRIKEOUT=0x08;
- const IS_UNDERLINE=0x10;
-
- /**
- * Bits indicating whether particular font states are changed.
- */
- const IS_SET_BOLD=0x01000;
- const IS_SET_ITALIC=0x02000;
- const IS_SET_OVERLINE=0x04000;
- const IS_SET_STRIKEOUT=0x08000;
- const IS_SET_UNDERLINE=0x10000;
- const IS_SET_SIZE=0x20000;
- const IS_SET_NAME=0x40000;
-
- /**
- * @var integer bits representing various states
- */
- private $_flags=0;
- /**
- * @var string font name
- */
- private $_name='';
- /**
- * @var string font size
- */
- private $_size='';
-
- /**
- * @return boolean whether the font is in bold face. Defaults to false.
- */
- public function getBold()
- {
- return ($this->_flags & self::IS_BOLD)!==0;
- }
-
- /**
- * @param boolean whether the font is in bold face
- */
- public function setBold($value)
- {
- $this->_flags |= self::IS_SET_BOLD;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_BOLD;
- else
- $this->_flags &= ~self::IS_BOLD;
- }
-
- /**
- * @return boolean whether the font is in italic face. Defaults to false.
- */
- public function getItalic()
- {
- return ($this->_flags & self::IS_ITALIC)!==0;
- }
-
- /**
- * @param boolean whether the font is italic
- */
- public function setItalic($value)
- {
- $this->_flags |= self::IS_SET_ITALIC;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_ITALIC;
- else
- $this->_flags &= ~self::IS_ITALIC;
- }
-
- /**
- * @return boolean whether the font is overlined. Defaults to false.
- */
- public function getOverline()
- {
- return ($this->_flags & self::IS_OVERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is overlined
- */
- public function setOverline($value)
- {
- $this->_flags |= self::IS_SET_OVERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_OVERLINE;
- else
- $this->_flags &= ~self::IS_OVERLINE;
- }
-
- /**
- * @return string the font size
- */
- public function getSize()
- {
- return $this->_size;
- }
-
- /**
- * @param string the font size
- */
- public function setSize($value)
- {
- $this->_flags |= self::IS_SET_SIZE;
- $this->_size=$value;
- }
-
- /**
- * @return boolean whether the font is strikeout. Defaults to false.
- */
- public function getStrikeout()
- {
- return ($this->_flags & self::IS_STRIKEOUT)!==0;
- }
-
- /**
- * @param boolean whether the font is strikeout
- */
- public function setStrikeout($value)
- {
- $this->_flags |= self::IS_SET_STRIKEOUT;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_STRIKEOUT;
- else
- $this->_flags &= ~self::IS_STRIKEOUT;
- }
-
- /**
- * @return boolean whether the font is underlined. Defaults to false.
- */
- public function getUnderline()
- {
- return ($this->_flags & self::IS_UNDERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is underlined
- */
- public function setUnderline($value)
- {
- $this->_flags |= self::IS_SET_UNDERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_UNDERLINE;
- else
- $this->_flags &= ~self::IS_UNDERLINE;
- }
-
- /**
- * @return string the font name (family)
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string the font name (family)
- */
- public function setName($value)
- {
- $this->_flags |= self::IS_SET_NAME;
- $this->_name=$value;
- }
-
- /**
- * @return boolean whether the font is empty
- */
- public function getIsEmpty()
- {
- return !$this->_flags;
- }
-
- /**
- * Clears up the font.
- */
- public function reset()
- {
- $this->_flags=0;
- $this->_name='';
- $this->_size='';
- }
-
- /**
- * Merges the font with a new one.
- * If a font field is not set in the font, it will be overwritten with
- * the new one.
- * @param TFont the new font
- */
- public function mergeWith($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
- $this->setBold($font->getBold());
- if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
- $this->setItalic($font->getItalic());
- if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
- $this->setOverline($font->getOverline());
- if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
- $this->setStrikeout($font->getStrikeout());
- if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
- $this->setUnderline($font->getUnderline());
- if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
- $this->setSize($font->getSize());
- if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
- $this->setName($font->getName());
- }
-
- /**
- * Copies the fields in a new font to this font.
- * If a font field is set in the new font, the corresponding field
- * in this font will be overwritten.
- * @param TFont the new font
- */
- public function copyFrom($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if($font->_flags & self::IS_SET_BOLD)
- $this->setBold($font->getBold());
- if($font->_flags & self::IS_SET_ITALIC)
- $this->setItalic($font->getItalic());
- if($font->_flags & self::IS_SET_OVERLINE)
- $this->setOverline($font->getOverline());
- if($font->_flags & self::IS_SET_STRIKEOUT)
- $this->setStrikeout($font->getStrikeout());
- if($font->_flags & self::IS_SET_UNDERLINE)
- $this->setUnderline($font->getUnderline());
- if($font->_flags & self::IS_SET_SIZE)
- $this->setSize($font->getSize());
- if($font->_flags & self::IS_SET_NAME)
- $this->setName($font->getName());
- }
-
- /**
- * @return string the font in a css style string representation.
- */
- public function toString()
- {
- if($this->_flags===0)
- return '';
- $str='';
- if($this->_flags & self::IS_SET_BOLD)
- $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
- if($this->_flags & self::IS_SET_ITALIC)
- $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $str.='text-decoration:'.$textDec.';';
- if($this->_size!=='')
- $str.='font-size:'.$this->_size.';';
- if($this->_name!=='')
- $str.='font-family:'.$this->_name.';';
- return $str;
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if($this->_flags===0)
- return;
- if($this->_flags & self::IS_SET_BOLD)
- $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
- if($this->_flags & self::IS_SET_ITALIC)
- $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $writer->addStyleAttribute('text-decoration',$textDec);
- if($this->_size!=='')
- $writer->addStyleAttribute('font-size',$this->_size);
- if($this->_name!=='')
- $writer->addStyleAttribute('font-family',$this->_name);
- }
-}
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFont class
+ *
+ * TFont encapsulates the CSS style fields related with font settings.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFont extends TComponent
+{
+ /**
+ * Bits indicating the font states.
+ */
+ const IS_BOLD=0x01;
+ const IS_ITALIC=0x02;
+ const IS_OVERLINE=0x04;
+ const IS_STRIKEOUT=0x08;
+ const IS_UNDERLINE=0x10;
+
+ /**
+ * Bits indicating whether particular font states are changed.
+ */
+ const IS_SET_BOLD=0x01000;
+ const IS_SET_ITALIC=0x02000;
+ const IS_SET_OVERLINE=0x04000;
+ const IS_SET_STRIKEOUT=0x08000;
+ const IS_SET_UNDERLINE=0x10000;
+ const IS_SET_SIZE=0x20000;
+ const IS_SET_NAME=0x40000;
+
+ /**
+ * @var integer bits representing various states
+ */
+ private $_flags=0;
+ /**
+ * @var string font name
+ */
+ private $_name='';
+ /**
+ * @var string font size
+ */
+ private $_size='';
+
+ /**
+ * @return boolean whether the font is in bold face. Defaults to false.
+ */
+ public function getBold()
+ {
+ return ($this->_flags & self::IS_BOLD)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is in bold face
+ */
+ public function setBold($value)
+ {
+ $this->_flags |= self::IS_SET_BOLD;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_BOLD;
+ else
+ $this->_flags &= ~self::IS_BOLD;
+ }
+
+ /**
+ * @return boolean whether the font is in italic face. Defaults to false.
+ */
+ public function getItalic()
+ {
+ return ($this->_flags & self::IS_ITALIC)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is italic
+ */
+ public function setItalic($value)
+ {
+ $this->_flags |= self::IS_SET_ITALIC;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_ITALIC;
+ else
+ $this->_flags &= ~self::IS_ITALIC;
+ }
+
+ /**
+ * @return boolean whether the font is overlined. Defaults to false.
+ */
+ public function getOverline()
+ {
+ return ($this->_flags & self::IS_OVERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is overlined
+ */
+ public function setOverline($value)
+ {
+ $this->_flags |= self::IS_SET_OVERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_OVERLINE;
+ else
+ $this->_flags &= ~self::IS_OVERLINE;
+ }
+
+ /**
+ * @return string the font size
+ */
+ public function getSize()
+ {
+ return $this->_size;
+ }
+
+ /**
+ * @param string the font size
+ */
+ public function setSize($value)
+ {
+ $this->_flags |= self::IS_SET_SIZE;
+ $this->_size=$value;
+ }
+
+ /**
+ * @return boolean whether the font is strikeout. Defaults to false.
+ */
+ public function getStrikeout()
+ {
+ return ($this->_flags & self::IS_STRIKEOUT)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is strikeout
+ */
+ public function setStrikeout($value)
+ {
+ $this->_flags |= self::IS_SET_STRIKEOUT;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_STRIKEOUT;
+ else
+ $this->_flags &= ~self::IS_STRIKEOUT;
+ }
+
+ /**
+ * @return boolean whether the font is underlined. Defaults to false.
+ */
+ public function getUnderline()
+ {
+ return ($this->_flags & self::IS_UNDERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is underlined
+ */
+ public function setUnderline($value)
+ {
+ $this->_flags |= self::IS_SET_UNDERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_UNDERLINE;
+ else
+ $this->_flags &= ~self::IS_UNDERLINE;
+ }
+
+ /**
+ * @return string the font name (family)
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string the font name (family)
+ */
+ public function setName($value)
+ {
+ $this->_flags |= self::IS_SET_NAME;
+ $this->_name=$value;
+ }
+
+ /**
+ * @return boolean whether the font is empty
+ */
+ public function getIsEmpty()
+ {
+ return !$this->_flags;
+ }
+
+ /**
+ * Clears up the font.
+ */
+ public function reset()
+ {
+ $this->_flags=0;
+ $this->_name='';
+ $this->_size='';
+ }
+
+ /**
+ * Merges the font with a new one.
+ * If a font field is not set in the font, it will be overwritten with
+ * the new one.
+ * @param TFont the new font
+ */
+ public function mergeWith($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
+ $this->setBold($font->getBold());
+ if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
+ $this->setItalic($font->getItalic());
+ if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
+ $this->setOverline($font->getOverline());
+ if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
+ $this->setStrikeout($font->getStrikeout());
+ if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
+ $this->setUnderline($font->getUnderline());
+ if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
+ $this->setSize($font->getSize());
+ if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
+ $this->setName($font->getName());
+ }
+
+ /**
+ * Copies the fields in a new font to this font.
+ * If a font field is set in the new font, the corresponding field
+ * in this font will be overwritten.
+ * @param TFont the new font
+ */
+ public function copyFrom($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if($font->_flags & self::IS_SET_BOLD)
+ $this->setBold($font->getBold());
+ if($font->_flags & self::IS_SET_ITALIC)
+ $this->setItalic($font->getItalic());
+ if($font->_flags & self::IS_SET_OVERLINE)
+ $this->setOverline($font->getOverline());
+ if($font->_flags & self::IS_SET_STRIKEOUT)
+ $this->setStrikeout($font->getStrikeout());
+ if($font->_flags & self::IS_SET_UNDERLINE)
+ $this->setUnderline($font->getUnderline());
+ if($font->_flags & self::IS_SET_SIZE)
+ $this->setSize($font->getSize());
+ if($font->_flags & self::IS_SET_NAME)
+ $this->setName($font->getName());
+ }
+
+ /**
+ * @return string the font in a css style string representation.
+ */
+ public function toString()
+ {
+ if($this->_flags===0)
+ return '';
+ $str='';
+ if($this->_flags & self::IS_SET_BOLD)
+ $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
+ if($this->_flags & self::IS_SET_ITALIC)
+ $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $str.='text-decoration:'.$textDec.';';
+ if($this->_size!=='')
+ $str.='font-size:'.$this->_size.';';
+ if($this->_name!=='')
+ $str.='font-family:'.$this->_name.';';
+ return $str;
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if($this->_flags===0)
+ return;
+ if($this->_flags & self::IS_SET_BOLD)
+ $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
+ if($this->_flags & self::IS_SET_ITALIC)
+ $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $writer->addStyleAttribute('text-decoration',$textDec);
+ if($this->_size!=='')
+ $writer->addStyleAttribute('font-size',$this->_size);
+ if($this->_name!=='')
+ $writer->addStyleAttribute('font-family',$this->_name);
+ }
+}
diff --git a/framework/Web/UI/WebControls/THead.php b/framework/Web/UI/WebControls/THead.php
index c0042c22..7966f2d3 100644
--- a/framework/Web/UI/WebControls/THead.php
+++ b/framework/Web/UI/WebControls/THead.php
@@ -1,377 +1,377 @@
- and Qiang Xue
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THead class
- *
- * THead displays a head element on a page. It displays the content
- * enclosed in its body and the page title set by the
- * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
- * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
- * {@link TClientScriptManager::registerHeadJavaScript}, and
- * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
- * in the head.
- * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
- * property. You can add a meta object to the collection in code dynamically,
- * or add it in template using the following syntax,
- *
- *
- *
- *
- *
- *
- *
- * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
- * the THead control currently on the page. A page can have at most one THead
- * control. Although not required, it is recommended to place a THead on your page.
- * Without a THead on the page, stylesheets and javascripts in the current page
- * theme will not be rendered.
- *
- * @author Marcus Nyeholt and Qiang Xue
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THead extends TControl
-{
- /**
- * @var TList list of meta name tags to be loaded by {@link THead}
- */
- private $_metaTags=null;
-
- /**
- * Registers the head control with the current page.
- * This method is invoked when the control enters 'Init' stage.
- * The method raises 'Init' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setHead($this);
- }
-
- /**
- * Processes an object that is created during parsing template.
- * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
- * collection of the head control.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- if($object instanceof TMetaTag)
- $this->getMetaTags()->add($object);
- else
- parent::addParsedObject($object);
- }
-
- /**
- * @return string the page title.
- */
- public function getTitle()
- {
- return $this->getViewState('Title','');
- }
-
- /**
- * Sets the page title.
- * This title will be rendered only if the {@link TPage::getTitle Title} property
- * of the page is empty.
- * @param string the page title.
- */
- public function setTitle($value)
- {
- $this->setViewState('Title',$value,'');
- }
-
- /**
- * @return string base URL of the page. This URL is rendered as the 'href' attribute of tag. Defaults to ''.
- */
- public function getBaseUrl()
- {
- return $this->getViewState('BaseUrl','');
- }
-
- /**
- * @param string base URL of the page. This URL is rendered as the 'href' attribute of tag.
- */
- public function setBaseUrl($url)
- {
- $this->setViewState('BaseUrl',$url,'');
- }
-
- /**
- * @return string the URL for the shortcut icon of the page. Defaults to ''.
- */
- public function getShortcutIcon()
- {
- return $this->getViewState('ShortcutIcon','');
- }
-
- /**
- * @param string the URL for the shortcut icon of the page.
- */
- public function setShortcutIcon($url)
- {
- $this->setViewState('ShortcutIcon',$url,'');
- }
-
- /**
- * @return TMetaTagCollection meta tag collection
- */
- public function getMetaTags()
- {
- if(($metaTags=$this->getViewState('MetaTags',null))===null)
- {
- $metaTags=new TMetaTagCollection;
- $this->setViewState('MetaTags',$metaTags,null);
- }
- return $metaTags;
- }
-
- /**
- * Renders the head control.
- * @param THtmlWriter the writer for rendering purpose.
- */
- public function render($writer)
- {
- $page=$this->getPage();
- $title=$this->getTitle();
- $writer->write("\n".THttpUtility::htmlEncode($title)." \n");
- if(($baseUrl=$this->getBaseUrl())!=='')
- $writer->write(' \n");
- if(($icon=$this->getShortcutIcon())!=='')
- $writer->write(' \n");
-
- if(($metaTags=$this->getMetaTags())!==null)
- {
- foreach($metaTags as $metaTag)
- {
- $metaTag->render($writer);
- $writer->writeLine();
- }
- }
- $cs=$page->getClientScript();
- $cs->renderStyleSheetFiles($writer);
- $cs->renderStyleSheets($writer);
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHeadScriptFiles($writer);
- $cs->renderHeadScripts($writer);
- }
- parent::render($writer);
- $writer->write("\n");
- }
-}
-
-/**
- * TMetaTag class.
- *
- * TMetaTag represents a meta tag appearing in a page head section.
- * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
- * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
- * properties, which correspond to id, http-equiv, name, content, and scheme
- * attributes for a meta tag, respectively.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTag extends TComponent
-{
- /**
- * @var string id of the meta tag
- */
- private $_id='';
- /**
- * @var string http-equiv attribute of the meta tag
- */
- private $_httpEquiv='';
- /**
- * @var string name attribute of the meta tag
- */
- private $_name='';
- /**
- * @var string content attribute of the meta tag
- */
- private $_content='';
- /**
- * @var string scheme attribute of the meta tag
- */
- private $_scheme='';
-
- /**
- * @return string id of the meta tag
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * @param string id of the meta tag
- */
- public function setID($value)
- {
- $this->_id=$value;
- }
-
- /**
- * @return string http-equiv attribute of the meta tag
- */
- public function getHttpEquiv()
- {
- return $this->_httpEquiv;
- }
-
- /**
- * @param string http-equiv attribute of the meta tag
- */
- public function setHttpEquiv($value)
- {
- $this->_httpEquiv=$value;
- }
-
- /**
- * @return string name attribute of the meta tag
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string name attribute of the meta tag
- */
- public function setName($value)
- {
- $this->_name=$value;
- }
-
- /**
- * @return string content attribute of the meta tag
- */
- public function getContent()
- {
- return $this->_content;
- }
-
- /**
- * @param string content attribute of the meta tag
- */
- public function setContent($value)
- {
- $this->_content=$value;
- }
-
- /**
- * @return string scheme attribute of the meta tag
- */
- public function getScheme()
- {
- return $this->_scheme;
- }
-
- /**
- * @param string scheme attribute of the meta tag
- */
- public function setScheme($value)
- {
- $this->_scheme=$value;
- }
-
- /**
- * Renders the meta tag.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_id!=='')
- $writer->addAttribute('id',$this->_id);
- if($this->_name!=='')
- $writer->addAttribute('name',$this->_name);
- if($this->_httpEquiv!=='')
- $writer->addAttribute('http-equiv',$this->_httpEquiv);
- if($this->_scheme!=='')
- $writer->addAttribute('scheme',$this->_scheme);
- $writer->addAttribute('content',$this->_content);
- $writer->renderBeginTag('meta');
- $writer->renderEndTag();
- }
-}
-
-
-/**
- * TMetaTagCollection class
- *
- * TMetaTagCollection represents a collection of meta tags
- * contained in a {@link THead} control.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTagCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing type
- * check on the item being added.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TMetaTag)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
- }
-
- /**
- * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
- * @param string the ID of the meta tag to be looked for
- * @return integer the index of the meta tag found, -1 if not found.
- */
- public function findIndexByID($id)
- {
- $index=0;
- foreach($this as $item)
- {
- if($item->getID()===$id)
- return $index;
- $index++;
- }
- return -1;
- }
-
- /**
- * Finds the item whose value is the one being looked for.
- * @param string the id of the meta tag to be looked for
- * @return TMetaTag the meta tag found, null if not found.
- */
- public function findMetaTagByID($id)
- {
- if(($index=$this->findIndexByID($id))>=0)
- return $this->itemAt($index);
- else
- return null;
- }
-}
-
-?>
+ and Qiang Xue
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * THead class
+ *
+ * THead displays a head element on a page. It displays the content
+ * enclosed in its body and the page title set by the
+ * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
+ * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
+ * {@link TClientScriptManager::registerHeadJavaScript}, and
+ * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
+ * in the head.
+ * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
+ * property. You can add a meta object to the collection in code dynamically,
+ * or add it in template using the following syntax,
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
+ * the THead control currently on the page. A page can have at most one THead
+ * control. Although not required, it is recommended to place a THead on your page.
+ * Without a THead on the page, stylesheets and javascripts in the current page
+ * theme will not be rendered.
+ *
+ * @author Marcus Nyeholt and Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THead extends TControl
+{
+ /**
+ * @var TList list of meta name tags to be loaded by {@link THead}
+ */
+ private $_metaTags=null;
+
+ /**
+ * Registers the head control with the current page.
+ * This method is invoked when the control enters 'Init' stage.
+ * The method raises 'Init' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setHead($this);
+ }
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
+ * collection of the head control.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TMetaTag)
+ $this->getMetaTags()->add($object);
+ else
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * @return string the page title.
+ */
+ public function getTitle()
+ {
+ return $this->getViewState('Title','');
+ }
+
+ /**
+ * Sets the page title.
+ * This title will be rendered only if the {@link TPage::getTitle Title} property
+ * of the page is empty.
+ * @param string the page title.
+ */
+ public function setTitle($value)
+ {
+ $this->setViewState('Title',$value,'');
+ }
+
+ /**
+ * @return string base URL of the page. This URL is rendered as the 'href' attribute of tag. Defaults to ''.
+ */
+ public function getBaseUrl()
+ {
+ return $this->getViewState('BaseUrl','');
+ }
+
+ /**
+ * @param string base URL of the page. This URL is rendered as the 'href' attribute of tag.
+ */
+ public function setBaseUrl($url)
+ {
+ $this->setViewState('BaseUrl',$url,'');
+ }
+
+ /**
+ * @return string the URL for the shortcut icon of the page. Defaults to ''.
+ */
+ public function getShortcutIcon()
+ {
+ return $this->getViewState('ShortcutIcon','');
+ }
+
+ /**
+ * @param string the URL for the shortcut icon of the page.
+ */
+ public function setShortcutIcon($url)
+ {
+ $this->setViewState('ShortcutIcon',$url,'');
+ }
+
+ /**
+ * @return TMetaTagCollection meta tag collection
+ */
+ public function getMetaTags()
+ {
+ if(($metaTags=$this->getViewState('MetaTags',null))===null)
+ {
+ $metaTags=new TMetaTagCollection;
+ $this->setViewState('MetaTags',$metaTags,null);
+ }
+ return $metaTags;
+ }
+
+ /**
+ * Renders the head control.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+ $title=$this->getTitle();
+ $writer->write("\n".THttpUtility::htmlEncode($title)." \n");
+ if(($baseUrl=$this->getBaseUrl())!=='')
+ $writer->write(' \n");
+ if(($icon=$this->getShortcutIcon())!=='')
+ $writer->write(' \n");
+
+ if(($metaTags=$this->getMetaTags())!==null)
+ {
+ foreach($metaTags as $metaTag)
+ {
+ $metaTag->render($writer);
+ $writer->writeLine();
+ }
+ }
+ $cs=$page->getClientScript();
+ $cs->renderStyleSheetFiles($writer);
+ $cs->renderStyleSheets($writer);
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHeadScriptFiles($writer);
+ $cs->renderHeadScripts($writer);
+ }
+ parent::render($writer);
+ $writer->write("\n");
+ }
+}
+
+/**
+ * TMetaTag class.
+ *
+ * TMetaTag represents a meta tag appearing in a page head section.
+ * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
+ * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
+ * properties, which correspond to id, http-equiv, name, content, and scheme
+ * attributes for a meta tag, respectively.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTag extends TComponent
+{
+ /**
+ * @var string id of the meta tag
+ */
+ private $_id='';
+ /**
+ * @var string http-equiv attribute of the meta tag
+ */
+ private $_httpEquiv='';
+ /**
+ * @var string name attribute of the meta tag
+ */
+ private $_name='';
+ /**
+ * @var string content attribute of the meta tag
+ */
+ private $_content='';
+ /**
+ * @var string scheme attribute of the meta tag
+ */
+ private $_scheme='';
+
+ /**
+ * @return string id of the meta tag
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of the meta tag
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string http-equiv attribute of the meta tag
+ */
+ public function getHttpEquiv()
+ {
+ return $this->_httpEquiv;
+ }
+
+ /**
+ * @param string http-equiv attribute of the meta tag
+ */
+ public function setHttpEquiv($value)
+ {
+ $this->_httpEquiv=$value;
+ }
+
+ /**
+ * @return string name attribute of the meta tag
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name attribute of the meta tag
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return string content attribute of the meta tag
+ */
+ public function getContent()
+ {
+ return $this->_content;
+ }
+
+ /**
+ * @param string content attribute of the meta tag
+ */
+ public function setContent($value)
+ {
+ $this->_content=$value;
+ }
+
+ /**
+ * @return string scheme attribute of the meta tag
+ */
+ public function getScheme()
+ {
+ return $this->_scheme;
+ }
+
+ /**
+ * @param string scheme attribute of the meta tag
+ */
+ public function setScheme($value)
+ {
+ $this->_scheme=$value;
+ }
+
+ /**
+ * Renders the meta tag.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_id!=='')
+ $writer->addAttribute('id',$this->_id);
+ if($this->_name!=='')
+ $writer->addAttribute('name',$this->_name);
+ if($this->_httpEquiv!=='')
+ $writer->addAttribute('http-equiv',$this->_httpEquiv);
+ if($this->_scheme!=='')
+ $writer->addAttribute('scheme',$this->_scheme);
+ $writer->addAttribute('content',$this->_content);
+ $writer->renderBeginTag('meta');
+ $writer->renderEndTag();
+ }
+}
+
+
+/**
+ * TMetaTagCollection class
+ *
+ * TMetaTagCollection represents a collection of meta tags
+ * contained in a {@link THead} control.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTagCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing type
+ * check on the item being added.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TMetaTag)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
+ }
+
+ /**
+ * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
+ * @param string the ID of the meta tag to be looked for
+ * @return integer the index of the meta tag found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ $index=0;
+ foreach($this as $item)
+ {
+ if($item->getID()===$id)
+ return $index;
+ $index++;
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the item whose value is the one being looked for.
+ * @param string the id of the meta tag to be looked for
+ * @return TMetaTag the meta tag found, null if not found.
+ */
+ public function findMetaTagByID($id)
+ {
+ if(($index=$this->findIndexByID($id))>=0)
+ return $this->itemAt($index);
+ else
+ return null;
+ }
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/THiddenField.php b/framework/Web/UI/WebControls/THiddenField.php
index ac8ddfff..ec330d54 100644
--- a/framework/Web/UI/WebControls/THiddenField.php
+++ b/framework/Web/UI/WebControls/THiddenField.php
@@ -1,117 +1,117 @@
-
- * @link http://www.xisc.com/
+
+ * @link http://www.xisc.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THiddenField class
- *
- * THiddenField displays a hidden input field on a Web page.
- * The value of the input field can be accessed via {@link getValue Value} property.
- * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
- * event will be raised.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
-{
- private $_dataChanged=false;
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THiddenField class
+ *
+ * THiddenField displays a hidden input field on a Web page.
+ * The value of the input field can be accessed via {@link getValue Value} property.
+ * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
+ * event will be raised.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
+{
+ private $_dataChanged=false;
private $_isValid=true;
-
- /**
- * @return string tag name of the hidden field.
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets focus to this control.
- * This method overrides the parent implementation by forbidding setting focus to this control.
- */
- public function focus()
- {
- throw new TNotSupportedException('hiddenfield_focus_unsupported');
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by rendering
- * the hidden field input element.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $uniqueID=$this->getUniqueID();
- $this->getPage()->ensureRenderInForm($this);
- $writer->addAttribute('type','hidden');
- if($uniqueID!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getID()!=='')
- $writer->addAttribute('id',$this->getClientID());
- if(($value=$this->getValue())!=='')
- $writer->addAttribute('value',$value);
-
- if($this->getHasAttributes())
- {
- foreach($this->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
-
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Loads hidden field data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=$values[$key];
- if($value===$this->getValue())
- return false;
- else
- {
- $this->setValue($value);
- return $this->_dataChanged=true;
- }
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getValue();
- }
-
+
+ /**
+ * @return string tag name of the hidden field.
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets focus to this control.
+ * This method overrides the parent implementation by forbidding setting focus to this control.
+ */
+ public function focus()
+ {
+ throw new TNotSupportedException('hiddenfield_focus_unsupported');
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by rendering
+ * the hidden field input element.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $uniqueID=$this->getUniqueID();
+ $this->getPage()->ensureRenderInForm($this);
+ $writer->addAttribute('type','hidden');
+ if($uniqueID!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getID()!=='')
+ $writer->addAttribute('id',$this->getClientID());
+ if(($value=$this->getValue())!=='')
+ $writer->addAttribute('value',$value);
+
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Loads hidden field data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=$values[$key];
+ if($value===$this->getValue())
+ return false;
+ else
+ {
+ $this->setValue($value);
+ return $this->_dataChanged=true;
+ }
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getValue();
+ }
+
/**
* Returns true if this control validated successfully.
* Defaults to true.
@@ -129,96 +129,96 @@ class THiddenField extends TControl implements IPostBackDataHandler, IValidatabl
$this->_isValid=TPropertyValue::ensureBoolean($value);
}
- /**
- * Raises postdata changed event.
- * This method calls {@link onValueChanged} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onValueChanged(null);
- }
-
- /**
- * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
- * The method raises 'OnValueChanged' event to fire up the event delegates.
- * If you override this method, be sure to call the parent implementation
- * so that the attached event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onValueChanged($param)
- {
- $this->raiseEvent('OnValueChanged',$this,$param);
- }
-
- /**
- * @return string the value of the THiddenField
- */
- public function getValue()
- {
- return $this->getViewState('Value','');
- }
-
- /**
- * Sets the value of the THiddenField
- * @param string the value to be set
- */
- public function setValue($value)
- {
- $this->setViewState('Value',$value,'');
- }
-
- /**
- * Returns the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getValue()}.
- * @return string value of the hidden field
- * @see getValue
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getValue();
- }
-
- /**
- * Sets the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setValue()}.
- * @param string value of the hidden field
- * @see setValue
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setValue($value);
- }
-
-
- /**
- * @return boolean whether theming is enabled for this control. Defaults to false.
- */
- public function getEnableTheming()
- {
- return false;
- }
-
- /**
- * @param boolean whether theming is enabled for this control.
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('hiddenfield_theming_unsupported');
- }
-
- /**
- * @param string Skin ID
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setSkinID($value)
- {
- throw new TNotSupportedException('hiddenfield_skinid_unsupported');
- }
-}
-
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onValueChanged} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onValueChanged(null);
+ }
+
+ /**
+ * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
+ * The method raises 'OnValueChanged' event to fire up the event delegates.
+ * If you override this method, be sure to call the parent implementation
+ * so that the attached event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onValueChanged($param)
+ {
+ $this->raiseEvent('OnValueChanged',$this,$param);
+ }
+
+ /**
+ * @return string the value of the THiddenField
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value','');
+ }
+
+ /**
+ * Sets the value of the THiddenField
+ * @param string the value to be set
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value',$value,'');
+ }
+
+ /**
+ * Returns the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getValue()}.
+ * @return string value of the hidden field
+ * @see getValue
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Sets the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setValue()}.
+ * @param string value of the hidden field
+ * @see setValue
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setValue($value);
+ }
+
+
+ /**
+ * @return boolean whether theming is enabled for this control. Defaults to false.
+ */
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ /**
+ * @param boolean whether theming is enabled for this control.
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('hiddenfield_theming_unsupported');
+ }
+
+ /**
+ * @param string Skin ID
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('hiddenfield_skinid_unsupported');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/THtmlElement.php b/framework/Web/UI/WebControls/THtmlElement.php
index 3889ee50..29cd0057 100644
--- a/framework/Web/UI/WebControls/THtmlElement.php
+++ b/framework/Web/UI/WebControls/THtmlElement.php
@@ -1,68 +1,68 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TWebControl');
-
-/**
- * THtmlElement class.
- *
- * THtmlElement represents a generic HTML element whose tag name is specified
- * via {@link setTagName TagName} property. Because THtmlElement extends from
- * {@link TWebControl}, it enjoys all its functionalities.
- *
- * To change the default tag your subclass should override {@link getDefaultTagName}
- *
- * @author Qiang Xue
- * @author Brad Anderson
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-class THtmlElement extends TWebControl
-{
- /**
- * @var the tag of this element
- */
- private $_tagName=null;
-
- /**
- * @return string the tag name of this control. Defaults to 'span'.
- */
- public function getTagName()
- {
- return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
- }
-
- /**
- * @param string the tag name of this control.
- */
- public function setTagName($value)
- {
- $this->_tagName=TPropertyValue::ensureString($value);
- }
-
- /**
- * This is the default tag when no other is specified
- * @return string the default tag
- */
- public function getDefaultTagName() {
- return 'span';
- }
-
- /**
- * This tells you if this TagName has deviated from the original
- * @return boolean true if TagName has deviated from the default.
- */
- public function getIsMutated() {
- return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
- }
-}
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TWebControl');
+
+/**
+ * THtmlElement class.
+ *
+ * THtmlElement represents a generic HTML element whose tag name is specified
+ * via {@link setTagName TagName} property. Because THtmlElement extends from
+ * {@link TWebControl}, it enjoys all its functionalities.
+ *
+ * To change the default tag your subclass should override {@link getDefaultTagName}
+ *
+ * @author Qiang Xue
+ * @author Brad Anderson
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+class THtmlElement extends TWebControl
+{
+ /**
+ * @var the tag of this element
+ */
+ private $_tagName=null;
+
+ /**
+ * @return string the tag name of this control. Defaults to 'span'.
+ */
+ public function getTagName()
+ {
+ return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
+ }
+
+ /**
+ * @param string the tag name of this control.
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * This is the default tag when no other is specified
+ * @return string the default tag
+ */
+ public function getDefaultTagName() {
+ return 'span';
+ }
+
+ /**
+ * This tells you if this TagName has deviated from the original
+ * @return boolean true if TagName has deviated from the default.
+ */
+ public function getIsMutated() {
+ return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
+ }
+}
diff --git a/framework/Web/UI/WebControls/THyperLink.php b/framework/Web/UI/WebControls/THyperLink.php
index 1e32d6c9..b745f7b0 100644
--- a/framework/Web/UI/WebControls/THyperLink.php
+++ b/framework/Web/UI/WebControls/THyperLink.php
@@ -1,227 +1,227 @@
-
- * @link http://www.xisc.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THyperLink class
- *
- * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
- * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
- * the {@link setText Text} property. It is also possible to display an image
- * by setting the {@link setImageUrl ImageUrl} property. In this case,
- * {@link getText Text} is displayed as the alternate text of the image.
- * The link target is specified via the {@link setTarget Target} property.
- * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
- * the content enclosed within the control tag will be rendered.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLink extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name of the hyperlink
- */
- protected function getTagName()
- {
- return 'a';
- }
-
- /**
- * Adds attributes related to a hyperlink element to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $isEnabled=$this->getEnabled(true);
- if($this->getEnabled() && !$isEnabled)
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
- $writer->addAttribute('href',$url);
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
-
- /**
- * Renders the body content of the hyperlink.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($imageUrl=$this->getImageUrl())==='')
- {
- if(($text=$this->getText())!=='')
- $writer->write(THttpUtility::htmlEncode($text));
- else if($this->getHasControls())
- parent::renderContents($writer);
- else
- $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
- }
- else
- {
- $this->createImage($imageUrl)->renderControl($writer);
- }
- }
-
- /**
- * Gets the TImage for rendering the ImageUrl property. This is not for
- * creating dynamic images.
- * @param string image url.
- * @return TImage image control for rendering.
- */
- protected function createImage($imageUrl)
- {
- $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
- $image->setImageUrl($imageUrl);
- if(($width=$this->getImageWidth())!=='')
- $image->setWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $image->setHeight($height);
- if(($toolTip=$this->getToolTip())!=='')
- $image->setToolTip($toolTip);
- if(($text=$this->getText())!=='')
- $image->setAlternateText($text);
- $image->setBorderWidth('0');
- return $image;
- }
-
- /**
- * @return string the text caption of the THyperLink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the THyperLink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * Sets the height of the image in the THyperLink
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewSTate('ImageHeight',$value,'');
- }
-
- /**
- * @return string the location of the image file for the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * Sets the location of image file of the THyperLink.
- * @param string the image file location
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * Sets the width of the image in the THyperLink
- * @param string width of the image
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the THyperLink component is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * Returns the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text caption
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text caption to be set
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-}
-
+
+ * @link http://www.xisc.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THyperLink class
+ *
+ * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
+ * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
+ * the {@link setText Text} property. It is also possible to display an image
+ * by setting the {@link setImageUrl ImageUrl} property. In this case,
+ * {@link getText Text} is displayed as the alternate text of the image.
+ * The link target is specified via the {@link setTarget Target} property.
+ * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
+ * the content enclosed within the control tag will be rendered.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLink extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of the hyperlink
+ */
+ protected function getTagName()
+ {
+ return 'a';
+ }
+
+ /**
+ * Adds attributes related to a hyperlink element to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $isEnabled=$this->getEnabled(true);
+ if($this->getEnabled() && !$isEnabled)
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
+ $writer->addAttribute('href',$url);
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+
+ /**
+ * Renders the body content of the hyperlink.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($imageUrl=$this->getImageUrl())==='')
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write(THttpUtility::htmlEncode($text));
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ else
+ $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
+ }
+ else
+ {
+ $this->createImage($imageUrl)->renderControl($writer);
+ }
+ }
+
+ /**
+ * Gets the TImage for rendering the ImageUrl property. This is not for
+ * creating dynamic images.
+ * @param string image url.
+ * @return TImage image control for rendering.
+ */
+ protected function createImage($imageUrl)
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
+ $image->setImageUrl($imageUrl);
+ if(($width=$this->getImageWidth())!=='')
+ $image->setWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $image->setHeight($height);
+ if(($toolTip=$this->getToolTip())!=='')
+ $image->setToolTip($toolTip);
+ if(($text=$this->getText())!=='')
+ $image->setAlternateText($text);
+ $image->setBorderWidth('0');
+ return $image;
+ }
+
+ /**
+ * @return string the text caption of the THyperLink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the THyperLink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * Sets the height of the image in the THyperLink
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewSTate('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string the location of the image file for the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * Sets the location of image file of the THyperLink.
+ * @param string the image file location
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * Sets the width of the image in the THyperLink
+ * @param string width of the image
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the THyperLink component is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text caption
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text caption to be set
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/THyperLinkColumn.php b/framework/Web/UI/WebControls/THyperLinkColumn.php
index a73880f1..faa4ce42 100644
--- a/framework/Web/UI/WebControls/THyperLinkColumn.php
+++ b/framework/Web/UI/WebControls/THyperLinkColumn.php
@@ -1,273 +1,273 @@
-
- * @link http://www.pradosoft.com/
- * @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-/**
- * THyperLink class file
- */
-Prado::using('System.Web.UI.WebControls.THyperLink');
-
-/**
- * THyperLinkColumn class
- *
- * THyperLinkColumn contains a hyperlink for each item in the column.
- * You can set the text and the url of the hyperlink by {@link setText Text}
- * and {@link setNavigateUrl NavigateUrl} properties, respectively.
- * You can also bind the text and url to specific data field in datasource
- * by setting {@link setDataTextField DataTextField} and
- * {@link setDataNavigateUrlField DataNavigateUrlField}.
- * Both can be formatted before rendering according to the
- * {@link setDataTextFormatString DataTextFormatString} and
- * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
- * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
- * are present, the latter takes precedence.
- * The same rule applies to {@link setNavigateUrl NavigateUrl} and
- * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
- *
- * The hyperlinks in the column can be accessed by one of the following two methods:
- *
- * $datagridItem->HyperLinkColumnID->HyperLink
- * $datagridItem->HyperLinkColumnID->Controls[0]
- *
- * The second method is possible because the hyperlink control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLinkColumn extends TDataGridColumn
-{
- /**
- * @return string the text caption of the hyperlink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the hyperlink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the hyperlink caption
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the hyperlink caption
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewState('ImageHeight',$value,'');
- }
-
- /**
- * @return string url of the image in the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string url of the image in the THyperLink
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * @param string width of the image in the THyperLink
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the hyperlink is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the hyperlink is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function getDataNavigateUrlField()
- {
- return $this->getViewState('DataNavigateUrlField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function setDataNavigateUrlField($value)
- {
- $this->setViewState('DataNavigateUrlField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function getDataNavigateUrlFormatString()
- {
- return $this->getViewState('DataNavigateUrlFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function setDataNavigateUrlFormatString($value)
- {
- $this->setViewState('DataNavigateUrlFormatString',$value,'');
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a hyperlink within the cell.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $link=new THyperLink;
- if(($url = $this->getImageUrl())!=='')
- {
- $link->setImageUrl($url);
- if(($width=$this->getImageWidth())!=='')
- $link->setImageWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $link->setImageHeight($height);
- }
- $link->setText($this->getText());
- $link->setNavigateUrl($this->getNavigateUrl());
- $link->setTarget($this->getTarget());
- if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
- $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- $cell->getControls()->add($link);
- $cell->registerObject('HyperLink',$link);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($field=$this->getDataTextField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
- $sender->setText($text);
- }
- if(($field=$this->getDataNavigateUrlField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
- $sender->setNavigateUrl($url);
- }
- }
-}
-
+
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright © 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+/**
+ * THyperLink class file
+ */
+Prado::using('System.Web.UI.WebControls.THyperLink');
+
+/**
+ * THyperLinkColumn class
+ *
+ * THyperLinkColumn contains a hyperlink for each item in the column.
+ * You can set the text and the url of the hyperlink by {@link setText Text}
+ * and {@link setNavigateUrl NavigateUrl} properties, respectively.
+ * You can also bind the text and url to specific data field in datasource
+ * by setting {@link setDataTextField DataTextField} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField}.
+ * Both can be formatted before rendering according to the
+ * {@link setDataTextFormatString DataTextFormatString} and
+ * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
+ * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
+ * are present, the latter takes precedence.
+ * The same rule applies to {@link setNavigateUrl NavigateUrl} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
+ *
+ * The hyperlinks in the column can be accessed by one of the following two methods:
+ *
+ * $datagridItem->HyperLinkColumnID->HyperLink
+ * $datagridItem->HyperLinkColumnID->Controls[0]
+ *
+ * The second method is possible because the hyperlink control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLinkColumn extends TDataGridColumn
+{
+ /**
+ * @return string the text caption of the hyperlink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the hyperlink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the hyperlink caption
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the hyperlink caption
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewState('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string url of the image in the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string url of the image in the THyperLink
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * @param string width of the image in the THyperLink
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the hyperlink is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the hyperlink is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function getDataNavigateUrlField()
+ {
+ return $this->getViewState('DataNavigateUrlField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function setDataNavigateUrlField($value)
+ {
+ $this->setViewState('DataNavigateUrlField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function getDataNavigateUrlFormatString()
+ {
+ return $this->getViewState('DataNavigateUrlFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function setDataNavigateUrlFormatString($value)
+ {
+ $this->setViewState('DataNavigateUrlFormatString',$value,'');
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a hyperlink within the cell.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $link=new THyperLink;
+ if(($url = $this->getImageUrl())!=='')
+ {
+ $link->setImageUrl($url);
+ if(($width=$this->getImageWidth())!=='')
+ $link->setImageWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $link->setImageHeight($height);
+ }
+ $link->setText($this->getText());
+ $link->setNavigateUrl($this->getNavigateUrl());
+ $link->setTarget($this->getTarget());
+ if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
+ $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($link);
+ $cell->registerObject('HyperLink',$link);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($field=$this->getDataTextField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
+ $sender->setText($text);
+ }
+ if(($field=$this->getDataNavigateUrlField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
+ $sender->setNavigateUrl($url);
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TImage.php b/framework/Web/UI/WebControls/TImage.php
index 37f9a050..c8dde281 100644
--- a/framework/Web/UI/WebControls/TImage.php
+++ b/framework/Web/UI/WebControls/TImage.php
@@ -1,157 +1,157 @@
-
- * @link http://www.pradosoft.com/
+
+ * @link http://www.pradosoft.com/
* @copyright Copyright © 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TImage class
- *
- * TImage displays an image on a page. The image is specified via the
- * {@link setImageUrl ImageUrl} property which takes a relative or absolute
- * URL to the image file. The alignment of the image displayed is set by
- * the {@link setImageAlign ImageAlign} property. To set alternative texts
- * or long description of the image, use {@link setAlternateText AlternateText}
- * or {@link setDescriptionUrl DescriptionUrl} property, respectively.
- *
- * @author Qiang Xue