summaryrefslogtreecommitdiff
path: root/framework/Web/UI
diff options
context:
space:
mode:
authorctrlaltca <>2012-07-12 11:21:01 +0000
committerctrlaltca <>2012-07-12 11:21:01 +0000
commit903ae8a581fac1e6917fc3e31d2ad8fb91df80c3 (patch)
treee08bf04f0823650a231227ac3499121270172a23 /framework/Web/UI
parent3e4e6e66aeb3f8fea4e1eb4237498ef9d2358f63 (diff)
standardize the use of unix eol; use svn properties to enforce native eol
Diffstat (limited to 'framework/Web/UI')
-rw-r--r--framework/Web/UI/ActiveControls/TActiveButton.php264
-rwxr-xr-xframework/Web/UI/ActiveControls/TActiveClientScript.php164
-rw-r--r--framework/Web/UI/ActiveControls/TActiveControlAdapter.php1150
-rw-r--r--framework/Web/UI/ActiveControls/TActiveCustomValidator.php530
-rw-r--r--framework/Web/UI/ActiveControls/TActiveLabel.php2
-rw-r--r--framework/Web/UI/ActiveControls/TActivePageAdapter.php802
-rw-r--r--framework/Web/UI/ActiveControls/TActivePanel.php200
-rw-r--r--framework/Web/UI/ActiveControls/TActiveRatingList.php266
-rw-r--r--framework/Web/UI/ActiveControls/TActiveTextBox.php250
-rw-r--r--framework/Web/UI/ActiveControls/TAutoComplete.php880
-rw-r--r--framework/Web/UI/ActiveControls/TBaseActiveControl.php784
-rw-r--r--framework/Web/UI/ActiveControls/TCallback.php202
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackClientScript.php1410
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackClientSide.php644
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackEventParameter.php174
-rw-r--r--framework/Web/UI/ActiveControls/TCallbackOptions.php106
-rw-r--r--framework/Web/UI/ActiveControls/TEventTriggeredCallback.php190
-rw-r--r--framework/Web/UI/ActiveControls/TInPlaceTextBox.php580
-rw-r--r--framework/Web/UI/ActiveControls/TTriggeredCallback.php142
-rw-r--r--framework/Web/UI/ActiveControls/TValueTriggeredCallback.php240
-rw-r--r--framework/Web/UI/TCachePageStatePersister.php400
-rw-r--r--framework/Web/UI/TCompositeControl.php74
-rw-r--r--framework/Web/UI/TControl.php4790
-rw-r--r--framework/Web/UI/TControlAdapter.php286
-rw-r--r--framework/Web/UI/TForm.php342
-rw-r--r--framework/Web/UI/THtmlWriter.php458
-rw-r--r--framework/Web/UI/TPage.php2682
-rw-r--r--framework/Web/UI/TPageStatePersister.php140
-rw-r--r--framework/Web/UI/TSessionPageStatePersister.php260
-rw-r--r--framework/Web/UI/TTemplateControl.php484
-rw-r--r--framework/Web/UI/TTemplateManager.php2150
-rw-r--r--framework/Web/UI/TThemeManager.php1034
-rw-r--r--framework/Web/UI/WebControls/TAccordion.php1488
-rw-r--r--framework/Web/UI/WebControls/TBaseDataList.php378
-rw-r--r--framework/Web/UI/WebControls/TBoundColumn.php498
-rw-r--r--framework/Web/UI/WebControls/TBulletedList.php982
-rw-r--r--framework/Web/UI/WebControls/TButton.php734
-rw-r--r--framework/Web/UI/WebControls/TButtonColumn.php554
-rw-r--r--framework/Web/UI/WebControls/TCaptcha.php990
-rw-r--r--framework/Web/UI/WebControls/TCaptchaValidator.php254
-rw-r--r--framework/Web/UI/WebControls/TCheckBox.php1026
-rw-r--r--framework/Web/UI/WebControls/TCheckBoxColumn.php244
-rw-r--r--framework/Web/UI/WebControls/TCheckBoxList.php998
-rw-r--r--framework/Web/UI/WebControls/TColorPicker.php580
-rw-r--r--framework/Web/UI/WebControls/TCompareValidator.php528
-rw-r--r--framework/Web/UI/WebControls/TConditional.php284
-rw-r--r--framework/Web/UI/WebControls/TContent.php92
-rw-r--r--framework/Web/UI/WebControls/TContentPlaceHolder.php94
-rw-r--r--framework/Web/UI/WebControls/TCustomValidator.php414
-rw-r--r--framework/Web/UI/WebControls/TDataBoundControl.php1174
-rw-r--r--framework/Web/UI/WebControls/TDataGrid.php4516
-rw-r--r--framework/Web/UI/WebControls/TDataGridColumn.php1134
-rw-r--r--framework/Web/UI/WebControls/TDataGridItemRenderer.php58
-rw-r--r--framework/Web/UI/WebControls/TDataGridPagerStyle.php510
-rw-r--r--framework/Web/UI/WebControls/TDataList.php3530
-rw-r--r--framework/Web/UI/WebControls/TDataListItemRenderer.php342
-rw-r--r--framework/Web/UI/WebControls/TDataRenderer.php102
-rw-r--r--framework/Web/UI/WebControls/TDataSourceControl.php234
-rw-r--r--framework/Web/UI/WebControls/TDataSourceView.php410
-rw-r--r--framework/Web/UI/WebControls/TDataTypeValidator.php280
-rw-r--r--framework/Web/UI/WebControls/TDatePicker.php1986
-rw-r--r--framework/Web/UI/WebControls/TDropDownList.php308
-rw-r--r--framework/Web/UI/WebControls/TDropDownListColumn.php640
-rw-r--r--framework/Web/UI/WebControls/TEditCommandColumn.php528
-rw-r--r--framework/Web/UI/WebControls/TEmailAddressValidator.php192
-rw-r--r--framework/Web/UI/WebControls/TExpression.php122
-rw-r--r--framework/Web/UI/WebControls/TFileUpload.php562
-rw-r--r--framework/Web/UI/WebControls/TFlushOutput.php170
-rw-r--r--framework/Web/UI/WebControls/TFont.php634
-rw-r--r--framework/Web/UI/WebControls/THead.php754
-rw-r--r--framework/Web/UI/WebControls/THiddenField.php410
-rw-r--r--framework/Web/UI/WebControls/THtmlElement.php136
-rw-r--r--framework/Web/UI/WebControls/THyperLink.php454
-rw-r--r--framework/Web/UI/WebControls/THyperLinkColumn.php546
-rw-r--r--framework/Web/UI/WebControls/TImage.php312
-rw-r--r--framework/Web/UI/WebControls/TImageButton.php882
-rw-r--r--framework/Web/UI/WebControls/TImageMap.php1672
-rw-r--r--framework/Web/UI/WebControls/TItemDataRenderer.php164
-rw-r--r--framework/Web/UI/WebControls/TJavascriptLogger.php186
-rw-r--r--framework/Web/UI/WebControls/TKeyboard.php378
-rw-r--r--framework/Web/UI/WebControls/TLabel.php306
-rw-r--r--framework/Web/UI/WebControls/TLinkButton.php666
-rw-r--r--framework/Web/UI/WebControls/TListBox.php486
-rw-r--r--framework/Web/UI/WebControls/TListControl.php1846
-rw-r--r--framework/Web/UI/WebControls/TListControlValidator.php448
-rw-r--r--framework/Web/UI/WebControls/TListItem.php366
-rw-r--r--framework/Web/UI/WebControls/TLiteral.php222
-rw-r--r--framework/Web/UI/WebControls/TLiteralColumn.php306
-rw-r--r--framework/Web/UI/WebControls/TMarkdown.php148
-rw-r--r--framework/Web/UI/WebControls/TMultiView.php756
-rw-r--r--framework/Web/UI/WebControls/TOutputCache.php1240
-rw-r--r--framework/Web/UI/WebControls/TPager.php1582
-rw-r--r--framework/Web/UI/WebControls/TPanel.php492
-rw-r--r--framework/Web/UI/WebControls/TPanelStyle.php554
-rw-r--r--framework/Web/UI/WebControls/TPlaceHolder.php54
-rw-r--r--framework/Web/UI/WebControls/TRadioButton.php638
-rw-r--r--framework/Web/UI/WebControls/TRangeValidator.php716
-rw-r--r--framework/Web/UI/WebControls/TRatingList.php718
-rw-r--r--framework/Web/UI/WebControls/TReCaptcha.php464
-rw-r--r--framework/Web/UI/WebControls/TReCaptchaValidator.php244
-rw-r--r--framework/Web/UI/WebControls/TRegularExpressionValidator.php288
-rw-r--r--framework/Web/UI/WebControls/TRepeatInfo.php1118
-rw-r--r--framework/Web/UI/WebControls/TRepeater.php2048
-rw-r--r--framework/Web/UI/WebControls/TRepeaterItemRenderer.php98
-rw-r--r--framework/Web/UI/WebControls/TRequiredFieldValidator.php274
-rw-r--r--framework/Web/UI/WebControls/TSafeHtml.php170
-rw-r--r--framework/Web/UI/WebControls/TSlider.php1148
-rw-r--r--framework/Web/UI/WebControls/TStatements.php124
-rw-r--r--framework/Web/UI/WebControls/TStyle.php1786
-rw-r--r--framework/Web/UI/WebControls/TTable.php818
-rw-r--r--framework/Web/UI/WebControls/TTableCell.php442
-rw-r--r--framework/Web/UI/WebControls/TTableFooterRow.php92
-rw-r--r--framework/Web/UI/WebControls/TTableHeaderCell.php246
-rw-r--r--framework/Web/UI/WebControls/TTableHeaderRow.php92
-rw-r--r--framework/Web/UI/WebControls/TTableRow.php414
-rw-r--r--framework/Web/UI/WebControls/TTemplateColumn.php510
-rw-r--r--framework/Web/UI/WebControls/TTextBox.php1304
-rw-r--r--framework/Web/UI/WebControls/TTextProcessor.php170
-rw-r--r--framework/Web/UI/WebControls/TValidationSummary.php1072
-rw-r--r--framework/Web/UI/WebControls/TWebControlAdapter.php140
-rw-r--r--framework/Web/UI/WebControls/TWizard.php4290
-rw-r--r--framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php308
-rw-r--r--framework/Web/UI/WebControls/assets/captcha.php448
123 files changed, 42598 insertions, 42598 deletions
diff --git a/framework/Web/UI/ActiveControls/TActiveButton.php b/framework/Web/UI/ActiveControls/TActiveButton.php
index aaa10168..15b33692 100644
--- a/framework/Web/UI/ActiveControls/TActiveButton.php
+++ b/framework/Web/UI/ActiveControls/TActiveButton.php
@@ -1,132 +1,132 @@
-<?php
-/**
- * TActiveButton class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveButton is the active control counter part to TButton.
- *
- * When a TActiveButton is clicked, rather than a normal post back request a
- * callback request is initiated.
- *
- * The {@link onCallback OnCallback} event is raised during a callback request
- * and it is raise <b>after</b> the {@link onClick OnClick} event.
- *
- * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate}
- * property is true, changing the {@link setText Text} property during callback request
- * will update the button's caption upon callback response completion.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
- * is true, it will invoke the page's {@link TPage::validate validate}
- * method first. It will raise {@link onClick OnClick} event first
- * and then the {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->raisePostBackEvent($param);
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Updates the button text on the client-side if the
- * {@link setEnableUpdate EnableUpdate} property is set to true.
- * @param string caption of the button
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveButton';
- }
-}
-
+<?php
+/**
+ * TActiveButton class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveButton is the active control counter part to TButton.
+ *
+ * When a TActiveButton is clicked, rather than a normal post back request a
+ * callback request is initiated.
+ *
+ * The {@link onCallback OnCallback} event is raised during a callback request
+ * and it is raise <b>after</b> the {@link onClick OnClick} event.
+ *
+ * When the {@link TBaseActiveCallbackControl::setEnableUpdate ActiveControl.EnableUpdate}
+ * property is true, changing the {@link setText Text} property during callback request
+ * will update the button's caption upon callback response completion.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveButton extends TButton implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler} interface. If {@link getCausesValidation CausesValidation}
+ * is true, it will invoke the page's {@link TPage::validate validate}
+ * method first. It will raise {@link onClick OnClick} event first
+ * and then the {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->raisePostBackEvent($param);
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Updates the button text on the client-side if the
+ * {@link setEnableUpdate EnableUpdate} property is set to true.
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->setAttribute($this, 'value', $value);
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveButton';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveClientScript.php b/framework/Web/UI/ActiveControls/TActiveClientScript.php
index 423918d9..2e58b6b0 100755
--- a/framework/Web/UI/ActiveControls/TActiveClientScript.php
+++ b/framework/Web/UI/ActiveControls/TActiveClientScript.php
@@ -1,82 +1,82 @@
-<?php
-/**
- * TActiveClientScript class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveClientScript class
- *
- * This is the active counterpart of the {@link TClientScript} class.
- *
- * TActiveClientScript has the ability to render itself on ajax
- * callbacks. This means that every variable or function declared in javascript
- * code will be available to the page.
- *
- * Beware that when rendered on normal (postback) or ajax callbacks, some
- * javascript code won't behave in the same way.
- * When rendered as part of a normal/postback response, scripts will execute instantly
- * where they are in the page and in a synchronous fashion.
- * Instead, when they are rendered as part of a callback response,
- * they will be executed when all DOM modifications are complete and any dynamic
- * script file includes are loaded, out-of-band and practically all blocks at once,
- * regardless of where they actually occour in the original template/markup code.
- * This can potentially hurt compatibility and graceful fallback.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
- * @package System.Web.UI.ActiveControls
- * @since 3.2
- */
-
-class TActiveClientScript extends TClientScript
-{
- /**
- * Renders the custom script file.
- * @param THtmLWriter the renderer
- */
- protected function renderCustomScriptFile($writer)
- {
- if(($scriptUrl = $this->getScriptUrl())!=='')
- {
- if($this->getPage()->getIsCallback())
- {
- $cs = $this->getPage()->getClientScript();
- $uniqueid=$this->ClientID.'_custom';
- if(!$cs->isScriptFileRegistered($uniqueid))
- $cs->registerScriptFile($uniqueid, $scriptUrl);
- } else {
- $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
- }
- }
- }
-
- /**
- * Registers the body content as javascript.
- * @param THtmlWriter the renderer
- */
- protected function renderCustomScript($writer)
- {
- if($this->getHasControls())
- {
- if($this->getPage()->getIsCallback())
- {
- $extWriter= $this->getPage()->getResponse()->createHtmlWriter();
- $extWriter->write("/*<![CDATA[*/\n");
- $this->renderChildren($extWriter);
- $extWriter->write("\n/*]]>*/");
- $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
- } else {
- $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
- $this->renderChildren($writer);
- $writer->write("\n/*]]>*/\n</script>\n");
- }
- }
- }
-}
+<?php
+/**
+ * TActiveClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveClientScript class
+ *
+ * This is the active counterpart of the {@link TClientScript} class.
+ *
+ * TActiveClientScript has the ability to render itself on ajax
+ * callbacks. This means that every variable or function declared in javascript
+ * code will be available to the page.
+ *
+ * Beware that when rendered on normal (postback) or ajax callbacks, some
+ * javascript code won't behave in the same way.
+ * When rendered as part of a normal/postback response, scripts will execute instantly
+ * where they are in the page and in a synchronous fashion.
+ * Instead, when they are rendered as part of a callback response,
+ * they will be executed when all DOM modifications are complete and any dynamic
+ * script file includes are loaded, out-of-band and practically all blocks at once,
+ * regardless of where they actually occour in the original template/markup code.
+ * This can potentially hurt compatibility and graceful fallback.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id: TActiveClientScript.php 3144 2012-05-19 10:07:03Z ctrlaltca $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.2
+ */
+
+class TActiveClientScript extends TClientScript
+{
+ /**
+ * Renders the custom script file.
+ * @param THtmLWriter the renderer
+ */
+ protected function renderCustomScriptFile($writer)
+ {
+ if(($scriptUrl = $this->getScriptUrl())!=='')
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $uniqueid=$this->ClientID.'_custom';
+ if(!$cs->isScriptFileRegistered($uniqueid))
+ $cs->registerScriptFile($uniqueid, $scriptUrl);
+ } else {
+ $writer->write("<script type=\"text/javascript\" src=\"$scriptUrl\"></script>\n");
+ }
+ }
+ }
+
+ /**
+ * Registers the body content as javascript.
+ * @param THtmlWriter the renderer
+ */
+ protected function renderCustomScript($writer)
+ {
+ if($this->getHasControls())
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $extWriter= $this->getPage()->getResponse()->createHtmlWriter();
+ $extWriter->write("/*<![CDATA[*/\n");
+ $this->renderChildren($extWriter);
+ $extWriter->write("\n/*]]>*/");
+ $this->getPage()->getCallbackClient()->appendScriptBlock($extWriter);
+ } else {
+ $writer->write("<script type=\"text/javascript\">\n/*<![CDATA[*/\n");
+ $this->renderChildren($writer);
+ $writer->write("\n/*]]>*/\n</script>\n");
+ }
+ }
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
index 8a0c8aec..7e7a82fe 100644
--- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php
@@ -1,575 +1,575 @@
-<?php
-/**
- * TActiveControlAdapter and TCallbackPageStateTracker class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/*
- * Load common active control options.
- */
-Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
-
-/**
- * TActiveControlAdapter class.
- *
- * Customize the parent TControl class for active control classes.
- * TActiveControlAdapter instantiates a common base active control class
- * throught the {@link getBaseActiveControl BaseActiveControl} property.
- * The type of BaseActiveControl can be provided in the second parameter in the
- * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
- * the control adapted implements ICallbackEventHandler.
- *
- * TActiveControlAdapter will tracking viewstate changes to update the
- * corresponding client-side properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveControlAdapter extends TControlAdapter
-{
- /**
- * @var string base active control class name.
- */
- private $_activeControlType;
- /**
- * @var TBaseActiveControl base active control instance.
- */
- private $_baseActiveControl;
- /**
- * @var TCallbackPageStateTracker view state tracker.
- */
- private $_stateTracker;
-
- /**
- * Constructor.
- * @param IActiveControl active control to adapt.
- * @param string Base active control class name.
- */
- public function __construct(IActiveControl $control, $baseCallbackClass=null)
- {
- parent::__construct($control);
- $this->setBaseControlClass($baseCallbackClass);
- }
-
- /**
- * @param string base active control instance
- */
- protected function setBaseControlClass($type)
- {
- if($type===null)
- {
- if($this->getControl() instanceof ICallbackEventHandler)
- $this->_activeControlType = 'TBaseActiveCallbackControl';
- else
- $this->_activeControlType = 'TBaseActiveControl';
- }
- else
- $this->_activeControlType = $type;
- }
-
- /**
- * Publish the ajax script
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- }
-
- /**
- * Renders the callback client scripts.
- */
- public function render($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('ajax');
- $this->renderCallbackClientScripts();
- if($this->_control->getVisible(false))
- {
- parent::render($writer);
- } else {
- $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>");
- }
- }
-
- /**
- * Register the callback clientscripts and sets the post loader IDs.
- */
- protected function renderCallbackClientScripts()
- {
- $cs = $this->getPage()->getClientScript();
- $key = 'Prado.CallbackRequest.addPostLoaders';
- if(!$cs->isEndScriptRegistered($key))
- {
- $data = $this->getPage()->getPostDataLoaders();
- if(count($data) > 0)
- {
- $options = TJavaScript::encode($data,false);
- $script = "Prado.CallbackRequest.addPostLoaders({$options});";
- $cs->registerEndScript($key, $script);
- }
- }
- }
-
- /**
- * @param TBaseActiveControl change base active control
- */
- public function setBaseActiveControl($control)
- {
- $this->_baseActiveControl=$control;
- }
-
- /**
- * @return TBaseActiveControl Common active control options.
- */
- public function getBaseActiveControl()
- {
- if($this->_baseActiveControl===null)
- {
- $type = $this->_activeControlType;
- $this->_baseActiveControl = new $type($this->getControl());
- }
- return $this->_baseActiveControl;
- }
-
- /**
- * @return boolean true if the viewstate needs to be tracked.
- */
- protected function getIsTrackingPageState()
- {
- if($this->getPage()->getIsCallback())
- {
- $target = $this->getPage()->getCallbackEventTarget();
- if($target instanceof ICallbackEventHandler)
- {
- $client = $target->getActiveControl()->getClientSide();
- return $client->getEnablePageStateUpdate();
- }
- }
- return false;
- }
-
- /**
- * Starts viewstate tracking if necessary after when controls has been loaded
- */
- public function onLoad($param)
- {
- if($this->getIsTrackingPageState())
- {
- $this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
- $this->_stateTracker->trackChanges();
- }
- parent::onLoad($param);
- }
-
- /**
- * Saves additional persistent control state. Respond to viewstate changes
- * if necessary.
- */
- public function saveState()
- {
- if(($this->_stateTracker!==null)
- && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
- {
- $this->_stateTracker->respondToChanges();
- }
- parent::saveState();
- }
-
- /**
- * @return TCallbackPageStateTracker state tracker.
- */
- public function getStateTracker()
- {
- return $this->_stateTracker;
- }
-}
-
-/**
- * TCallbackPageStateTracker class.
- *
- * Tracking changes to the page state during callback.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackPageStateTracker
-{
- /**
- * @var TMap new view state data
- */
- private $_states;
- /**
- * @var TMap old view state data
- */
- private $_existingState;
- /**
- * @var TControl the control tracked
- */
- private $_control;
- /**
- * @var object null object.
- */
- private $_nullObject;
-
- /**
- * Constructor. Add a set of default states to track.
- * @param TControl control to track.
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_existingState = new TMap;
- $this->_nullObject = new stdClass;
- $this->_states = new TMap;
- $this->addStatesToTrack();
- }
-
- /**
- * Add a list of view states to track. Each state is added
- * to the StatesToTrack property with the view state name as key.
- * The value should be an array with two enteries. The first entery
- * is the name of the class that will calculate the state differences.
- * The second entry is a php function/method callback that handles
- * the changes in the viewstate.
- */
- protected function addStatesToTrack()
- {
- $states = $this->getStatesToTrack();
- $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
- $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
- $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
- $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
- $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
- $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
- $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
- }
-
- /**
- * @return TMap list of viewstates to track.
- */
- protected function getStatesToTrack()
- {
- return $this->_states;
- }
-
- /**
- * Start tracking view state changes. The clone function on objects are called
- * for those viewstate having an object as value.
- */
- public function trackChanges()
- {
- foreach($this->_states as $name => $value)
- {
- $obj = $this->_control->getViewState($name);
- $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
- }
- }
-
- /**
- * @return array list of viewstate and the changed data.
- */
- protected function getChanges()
- {
- $changes = array();
- foreach($this->_states as $name => $details)
- {
- $new = $this->_control->getViewState($name);
- $old = $this->_existingState[$name];
- if($new !== $old)
- {
- $diff = new $details[0]($new, $old, $this->_nullObject);
- if(($change = $diff->getDifference()) !== $this->_nullObject)
- $changes[] = array($details[1],array($change));
- }
- }
- return $changes;
- }
-
- /**
- * For each of the changes call the corresponding change handlers.
- */
- public function respondToChanges()
- {
- foreach($this->getChanges() as $change)
- call_user_func_array($change[0], $change[1]);
- }
-
- /**
- * @return TCallbackClientScript callback client scripting
- */
- protected function client()
- {
- return $this->_control->getPage()->getCallbackClient();
- }
-
- /**
- * Updates the tooltip.
- * @param string new tooltip
- */
- protected function updateToolTip($value)
- {
- $this->client()->setAttribute($this->_control, 'title', $value);
- }
-
- /**
- * Updates the tab index.
- * @param integer tab index
- */
- protected function updateTabIndex($value)
- {
- $this->client()->setAttribute($this->_control, 'tabindex', $value);
- }
-
- /**
- * Updates the modifier access key
- * @param string access key
- */
- protected function updateAccessKey($value)
- {
- $this->client()->setAttribute($this->_control, 'accesskey', $value);
- }
-
- /**
- * Hides or shows the control on the client-side. The control must be
- * already rendered on the client-side.
- * @param boolean true to show the control, false to hide.
- */
- protected function updateVisible($visible)
- {
- if($visible === false)
- $this->client()->replaceContent($this->_control,"<span id=\"".$this->_control->getClientID()."\" style=\"display:none\" ></span>");
- else
- $this->client()->replaceContent($this->_control,$this->_control);
- }
-
- /**
- * Enables or Disables the control on the client-side.
- * @param boolean true to enable the control, false to disable.
- */
- protected function updateEnabled($enable)
- {
- $this->client()->setAttribute($this->_control, 'disabled', $enable===false);
- }
-
- /**
- * Updates the CSS style on the control on the client-side.
- * @param array list of new CSS style declarations.
- */
- protected function updateStyle($style)
- {
- if($style['CssClass']!==null)
- $this->client()->setAttribute($this->_control, 'class', $style['CssClass']);
- if(count($style['Style']) > 0)
- $this->client()->setStyle($this->_control, $style['Style']);
- }
-
- /**
- * Updates/adds a list of attributes on the control.
- * @param array list of attribute name-value pairs.
- */
- protected function updateAttributes($attributes)
- {
- foreach($attributes as $name => $value)
- $this->client()->setAttribute($this->_control, $name, $value);
- }
-}
-
-/**
- * Calculates the viewstate changes during the request.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TViewStateDiff
-{
- /**
- * @var mixed updated viewstate
- */
- protected $_new;
- /**
- * @var mixed viewstate value at the begining of the request.
- */
- protected $_old;
- /**
- * @var object null value.
- */
- protected $_null;
-
- /**
- * Constructor.
- * @param mixed updated viewstate value.
- * @param mixed viewstate value at the begining of the request.
- * @param object representing the null value.
- */
- public function __construct($new, $old, $null)
- {
- $this->_new = $new;
- $this->_old = $old;
- $this->_null = $null;
- }
-
- /**
- * @return mixed view state changes, nullObject if no difference.
- */
- public abstract function getDifference();
-}
-
-/**
- * TScalarDiff class.
- *
- * Calculate the changes to a scalar value.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TScalarDiff extends TViewStateDiff
-{
- /**
- * @return mixed update viewstate value.
- */
- public function getDifference()
- {
- if(gettype($this->_new) === gettype($this->_old)
- && $this->_new === $this->_old)
- return $this->_null;
- else
- return $this->_new;
- }
-}
-
-/**
- * TStyleDiff class.
- *
- * Calculates the changes to the Style properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TStyleDiff extends TViewStateDiff
-{
- /**
- * @param TStyle control style
- * @return array all the style properties combined.
- */
- protected function getCombinedStyle($obj)
- {
- if(!($obj instanceof TStyle))
- return array();
- $style = $obj->getStyleFields();
- $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
- if($obj->hasFont())
- $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
- return $style;
- }
-
- /**
- * @param string CSS custom style string.
- * @param array CSS style as name-value array.
- */
- protected function getStyleFromString($string)
- {
- $style = array();
- if(!is_string($string)) return $style;
-
- foreach(explode(';',$string) as $sub)
- {
- $arr=explode(':',$sub);
- if(isset($arr[1]) && trim($arr[0])!=='')
- $style[trim($arr[0])] = trim($arr[1]);
- }
- return $style;
- }
-
- /**
- * @return string changes to the CSS class name.
- */
- protected function getCssClassDiff()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) && $this->_new->hasCssClass()
- ? $this->_new->getCssClass() : null;
- }
- else
- {
- return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
- $this->_new->getCssClass() : null;
- }
- }
-
- /**
- * @return array list of changes to the control style.
- */
- protected function getStyleDiff()
- {
- $diff = array_diff_assoc(
- $this->getCombinedStyle($this->_new),
- $this->getCombinedStyle($this->_old));
- return count($diff) > 0 ? $diff : null;
- }
-
- /**
- * @return array list of changes to the control style and CSS class name.
- */
- public function getDifference()
- {
- if($this->_new===null)
- return $this->_null;
- else
- {
- $css = $this->getCssClassDiff();
- $style = $this->getStyleDiff();
- if(($css!==null) || ($style!==null))
- return array('CssClass' => $css, 'Style' => $style);
- else
- $this->_null;
- }
- }
-}
-
-/**
- * TAttributesDiff class.
- *
- * Calculate the changes to attributes collection.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TMapCollectionDiff extends TViewStateDiff
-{
- /**
- * @return array updates to the attributes collection.
- */
- public function getDifference()
- {
- if($this->_old===null)
- {
- return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
- }
- else
- {
- $new = $this->_new->toArray();
- $old = $this->_old->toArray();
- $diff = array_diff_assoc($new, $old);
- return count($diff) > 0 ? $diff : $this->_null;
- }
- }
-}
-
+<?php
+/**
+ * TActiveControlAdapter and TCallbackPageStateTracker class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/*
+ * Load common active control options.
+ */
+Prado::using('System.Web.UI.ActiveControls.TBaseActiveControl');
+
+/**
+ * TActiveControlAdapter class.
+ *
+ * Customize the parent TControl class for active control classes.
+ * TActiveControlAdapter instantiates a common base active control class
+ * throught the {@link getBaseActiveControl BaseActiveControl} property.
+ * The type of BaseActiveControl can be provided in the second parameter in the
+ * constructor. Default is TBaseActiveControl or TBaseActiveCallbackControl if
+ * the control adapted implements ICallbackEventHandler.
+ *
+ * TActiveControlAdapter will tracking viewstate changes to update the
+ * corresponding client-side properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveControlAdapter extends TControlAdapter
+{
+ /**
+ * @var string base active control class name.
+ */
+ private $_activeControlType;
+ /**
+ * @var TBaseActiveControl base active control instance.
+ */
+ private $_baseActiveControl;
+ /**
+ * @var TCallbackPageStateTracker view state tracker.
+ */
+ private $_stateTracker;
+
+ /**
+ * Constructor.
+ * @param IActiveControl active control to adapt.
+ * @param string Base active control class name.
+ */
+ public function __construct(IActiveControl $control, $baseCallbackClass=null)
+ {
+ parent::__construct($control);
+ $this->setBaseControlClass($baseCallbackClass);
+ }
+
+ /**
+ * @param string base active control instance
+ */
+ protected function setBaseControlClass($type)
+ {
+ if($type===null)
+ {
+ if($this->getControl() instanceof ICallbackEventHandler)
+ $this->_activeControlType = 'TBaseActiveCallbackControl';
+ else
+ $this->_activeControlType = 'TBaseActiveControl';
+ }
+ else
+ $this->_activeControlType = $type;
+ }
+
+ /**
+ * Publish the ajax script
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Renders the callback client scripts.
+ */
+ public function render($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('ajax');
+ $this->renderCallbackClientScripts();
+ if($this->_control->getVisible(false))
+ {
+ parent::render($writer);
+ } else {
+ $writer->write("<span id=\"".$this->_control->getClientID()."\" style=\"display:none\"></span>");
+ }
+ }
+
+ /**
+ * Register the callback clientscripts and sets the post loader IDs.
+ */
+ protected function renderCallbackClientScripts()
+ {
+ $cs = $this->getPage()->getClientScript();
+ $key = 'Prado.CallbackRequest.addPostLoaders';
+ if(!$cs->isEndScriptRegistered($key))
+ {
+ $data = $this->getPage()->getPostDataLoaders();
+ if(count($data) > 0)
+ {
+ $options = TJavaScript::encode($data,false);
+ $script = "Prado.CallbackRequest.addPostLoaders({$options});";
+ $cs->registerEndScript($key, $script);
+ }
+ }
+ }
+
+ /**
+ * @param TBaseActiveControl change base active control
+ */
+ public function setBaseActiveControl($control)
+ {
+ $this->_baseActiveControl=$control;
+ }
+
+ /**
+ * @return TBaseActiveControl Common active control options.
+ */
+ public function getBaseActiveControl()
+ {
+ if($this->_baseActiveControl===null)
+ {
+ $type = $this->_activeControlType;
+ $this->_baseActiveControl = new $type($this->getControl());
+ }
+ return $this->_baseActiveControl;
+ }
+
+ /**
+ * @return boolean true if the viewstate needs to be tracked.
+ */
+ protected function getIsTrackingPageState()
+ {
+ if($this->getPage()->getIsCallback())
+ {
+ $target = $this->getPage()->getCallbackEventTarget();
+ if($target instanceof ICallbackEventHandler)
+ {
+ $client = $target->getActiveControl()->getClientSide();
+ return $client->getEnablePageStateUpdate();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Starts viewstate tracking if necessary after when controls has been loaded
+ */
+ public function onLoad($param)
+ {
+ if($this->getIsTrackingPageState())
+ {
+ $this->_stateTracker = new TCallbackPageStateTracker($this->getControl());
+ $this->_stateTracker->trackChanges();
+ }
+ parent::onLoad($param);
+ }
+
+ /**
+ * Saves additional persistent control state. Respond to viewstate changes
+ * if necessary.
+ */
+ public function saveState()
+ {
+ if(($this->_stateTracker!==null)
+ && $this->getControl()->getActiveControl()->canUpdateClientSide(true))
+ {
+ $this->_stateTracker->respondToChanges();
+ }
+ parent::saveState();
+ }
+
+ /**
+ * @return TCallbackPageStateTracker state tracker.
+ */
+ public function getStateTracker()
+ {
+ return $this->_stateTracker;
+ }
+}
+
+/**
+ * TCallbackPageStateTracker class.
+ *
+ * Tracking changes to the page state during callback.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackPageStateTracker
+{
+ /**
+ * @var TMap new view state data
+ */
+ private $_states;
+ /**
+ * @var TMap old view state data
+ */
+ private $_existingState;
+ /**
+ * @var TControl the control tracked
+ */
+ private $_control;
+ /**
+ * @var object null object.
+ */
+ private $_nullObject;
+
+ /**
+ * Constructor. Add a set of default states to track.
+ * @param TControl control to track.
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_existingState = new TMap;
+ $this->_nullObject = new stdClass;
+ $this->_states = new TMap;
+ $this->addStatesToTrack();
+ }
+
+ /**
+ * Add a list of view states to track. Each state is added
+ * to the StatesToTrack property with the view state name as key.
+ * The value should be an array with two enteries. The first entery
+ * is the name of the class that will calculate the state differences.
+ * The second entry is a php function/method callback that handles
+ * the changes in the viewstate.
+ */
+ protected function addStatesToTrack()
+ {
+ $states = $this->getStatesToTrack();
+ $states['Visible'] = array('TScalarDiff', array($this, 'updateVisible'));
+ $states['Enabled'] = array('TScalarDiff', array($this, 'updateEnabled'));
+ $states['Attributes'] = array('TMapCollectionDiff', array($this, 'updateAttributes'));
+ $states['Style'] = array('TStyleDiff', array($this, 'updateStyle'));
+ $states['TabIndex'] = array('TScalarDiff', array($this, 'updateTabIndex'));
+ $states['ToolTip'] = array('TScalarDiff', array($this, 'updateToolTip'));
+ $states['AccessKey'] = array('TScalarDiff', array($this, 'updateAccessKey'));
+ }
+
+ /**
+ * @return TMap list of viewstates to track.
+ */
+ protected function getStatesToTrack()
+ {
+ return $this->_states;
+ }
+
+ /**
+ * Start tracking view state changes. The clone function on objects are called
+ * for those viewstate having an object as value.
+ */
+ public function trackChanges()
+ {
+ foreach($this->_states as $name => $value)
+ {
+ $obj = $this->_control->getViewState($name);
+ $this->_existingState[$name] = is_object($obj) ? clone($obj) : $obj;
+ }
+ }
+
+ /**
+ * @return array list of viewstate and the changed data.
+ */
+ protected function getChanges()
+ {
+ $changes = array();
+ foreach($this->_states as $name => $details)
+ {
+ $new = $this->_control->getViewState($name);
+ $old = $this->_existingState[$name];
+ if($new !== $old)
+ {
+ $diff = new $details[0]($new, $old, $this->_nullObject);
+ if(($change = $diff->getDifference()) !== $this->_nullObject)
+ $changes[] = array($details[1],array($change));
+ }
+ }
+ return $changes;
+ }
+
+ /**
+ * For each of the changes call the corresponding change handlers.
+ */
+ public function respondToChanges()
+ {
+ foreach($this->getChanges() as $change)
+ call_user_func_array($change[0], $change[1]);
+ }
+
+ /**
+ * @return TCallbackClientScript callback client scripting
+ */
+ protected function client()
+ {
+ return $this->_control->getPage()->getCallbackClient();
+ }
+
+ /**
+ * Updates the tooltip.
+ * @param string new tooltip
+ */
+ protected function updateToolTip($value)
+ {
+ $this->client()->setAttribute($this->_control, 'title', $value);
+ }
+
+ /**
+ * Updates the tab index.
+ * @param integer tab index
+ */
+ protected function updateTabIndex($value)
+ {
+ $this->client()->setAttribute($this->_control, 'tabindex', $value);
+ }
+
+ /**
+ * Updates the modifier access key
+ * @param string access key
+ */
+ protected function updateAccessKey($value)
+ {
+ $this->client()->setAttribute($this->_control, 'accesskey', $value);
+ }
+
+ /**
+ * Hides or shows the control on the client-side. The control must be
+ * already rendered on the client-side.
+ * @param boolean true to show the control, false to hide.
+ */
+ protected function updateVisible($visible)
+ {
+ if($visible === false)
+ $this->client()->replaceContent($this->_control,"<span id=\"".$this->_control->getClientID()."\" style=\"display:none\" ></span>");
+ else
+ $this->client()->replaceContent($this->_control,$this->_control);
+ }
+
+ /**
+ * Enables or Disables the control on the client-side.
+ * @param boolean true to enable the control, false to disable.
+ */
+ protected function updateEnabled($enable)
+ {
+ $this->client()->setAttribute($this->_control, 'disabled', $enable===false);
+ }
+
+ /**
+ * Updates the CSS style on the control on the client-side.
+ * @param array list of new CSS style declarations.
+ */
+ protected function updateStyle($style)
+ {
+ if($style['CssClass']!==null)
+ $this->client()->setAttribute($this->_control, 'class', $style['CssClass']);
+ if(count($style['Style']) > 0)
+ $this->client()->setStyle($this->_control, $style['Style']);
+ }
+
+ /**
+ * Updates/adds a list of attributes on the control.
+ * @param array list of attribute name-value pairs.
+ */
+ protected function updateAttributes($attributes)
+ {
+ foreach($attributes as $name => $value)
+ $this->client()->setAttribute($this->_control, $name, $value);
+ }
+}
+
+/**
+ * Calculates the viewstate changes during the request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TViewStateDiff
+{
+ /**
+ * @var mixed updated viewstate
+ */
+ protected $_new;
+ /**
+ * @var mixed viewstate value at the begining of the request.
+ */
+ protected $_old;
+ /**
+ * @var object null value.
+ */
+ protected $_null;
+
+ /**
+ * Constructor.
+ * @param mixed updated viewstate value.
+ * @param mixed viewstate value at the begining of the request.
+ * @param object representing the null value.
+ */
+ public function __construct($new, $old, $null)
+ {
+ $this->_new = $new;
+ $this->_old = $old;
+ $this->_null = $null;
+ }
+
+ /**
+ * @return mixed view state changes, nullObject if no difference.
+ */
+ public abstract function getDifference();
+}
+
+/**
+ * TScalarDiff class.
+ *
+ * Calculate the changes to a scalar value.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TScalarDiff extends TViewStateDiff
+{
+ /**
+ * @return mixed update viewstate value.
+ */
+ public function getDifference()
+ {
+ if(gettype($this->_new) === gettype($this->_old)
+ && $this->_new === $this->_old)
+ return $this->_null;
+ else
+ return $this->_new;
+ }
+}
+
+/**
+ * TStyleDiff class.
+ *
+ * Calculates the changes to the Style properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TStyleDiff extends TViewStateDiff
+{
+ /**
+ * @param TStyle control style
+ * @return array all the style properties combined.
+ */
+ protected function getCombinedStyle($obj)
+ {
+ if(!($obj instanceof TStyle))
+ return array();
+ $style = $obj->getStyleFields();
+ $style = array_merge($style,$this->getStyleFromString($obj->getCustomStyle()));
+ if($obj->hasFont())
+ $style = array_merge($style, $this->getStyleFromString($obj->getFont()->toString()));
+ return $style;
+ }
+
+ /**
+ * @param string CSS custom style string.
+ * @param array CSS style as name-value array.
+ */
+ protected function getStyleFromString($string)
+ {
+ $style = array();
+ if(!is_string($string)) return $style;
+
+ foreach(explode(';',$string) as $sub)
+ {
+ $arr=explode(':',$sub);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $style[trim($arr[0])] = trim($arr[1]);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string changes to the CSS class name.
+ */
+ protected function getCssClassDiff()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) && $this->_new->hasCssClass()
+ ? $this->_new->getCssClass() : null;
+ }
+ else
+ {
+ return $this->_old->getCssClass() !== $this->_new->getCssClass() ?
+ $this->_new->getCssClass() : null;
+ }
+ }
+
+ /**
+ * @return array list of changes to the control style.
+ */
+ protected function getStyleDiff()
+ {
+ $diff = array_diff_assoc(
+ $this->getCombinedStyle($this->_new),
+ $this->getCombinedStyle($this->_old));
+ return count($diff) > 0 ? $diff : null;
+ }
+
+ /**
+ * @return array list of changes to the control style and CSS class name.
+ */
+ public function getDifference()
+ {
+ if($this->_new===null)
+ return $this->_null;
+ else
+ {
+ $css = $this->getCssClassDiff();
+ $style = $this->getStyleDiff();
+ if(($css!==null) || ($style!==null))
+ return array('CssClass' => $css, 'Style' => $style);
+ else
+ $this->_null;
+ }
+ }
+}
+
+/**
+ * TAttributesDiff class.
+ *
+ * Calculate the changes to attributes collection.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TMapCollectionDiff extends TViewStateDiff
+{
+ /**
+ * @return array updates to the attributes collection.
+ */
+ public function getDifference()
+ {
+ if($this->_old===null)
+ {
+ return ($this->_new!==null) ? $this->_new->toArray() : $this->_null;
+ }
+ else
+ {
+ $new = $this->_new->toArray();
+ $old = $this->_old->toArray();
+ $diff = array_diff_assoc($new, $old);
+ return count($diff) > 0 ? $diff : $this->_null;
+ }
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
index 9e09eb88..df8f45d9 100644
--- a/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
+++ b/framework/Web/UI/ActiveControls/TActiveCustomValidator.php
@@ -1,265 +1,265 @@
-<?php
-/**
- * TActiveCustomValidator class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TActiveCustomValidator Class
- *
- * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
- * validation event. The client-side uses callbacks to raise
- * the {@link onServerValidate onServerValidate} event.
- *
- * Beware that the {@link onServerValidate onServerValidate} may be
- * raised when the control to validate on the client side
- * changes value, that is, the server validation may be called many times.
- *
- * After the callback or postback, the {@link onServerValidate onServerValidate}
- * is raised once more. The {@link getIsCallback IsCallback} property
- * will be true when validation is made during a callback request.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidator extends TCustomValidator
- implements ICallbackEventHandler, IActiveControl
-{
- /**
- * @var boolean true if validation is made during a callback request.
- */
- private $_isCallback = false;
-
- /**
- * @return boolean true if validation is made during a callback request.
- */
- public function getIsCallback()
- {
- return $this->_isCallback;
- }
-
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client validation function is NOT supported.
- */
- public function setClientValidationFunction($value)
- {
- throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
- get_class($this));
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface. The {@link onServerValidate
- * OnServerValidate} event is raised first and then the
- * {@link onCallback OnCallback} event.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->_isCallback = true;
- $result = $this->onServerValidate($param->getCallbackParameter());
- $param->setResponseData($result);
- $this->onCallback($param);
- }
-
- /**
- * @param boolean whether the value is valid; this method will trigger a clientside update if needed
- */
- public function setIsValid($value)
- {
- parent::setIsValid($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.updateActiveCustomValidator';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=TBaseValidator::getClientScriptOptions();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-
- /**
- * Sets the text for the error message. Updates client-side erorr message.
- * @param string the error message
- */
- public function setErrorMessage($value)
- {
- parent::setErrorMessage($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $func = 'Prado.Validation.setErrorMessage';
- $client->callClientFunction($func, array($this, $value));
- }
- }
-
-
- /**
- * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
- * @return boolean whether client-side validation is enabled.
- */
- public function getEnableClientScript()
- {
- return true;
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- TBaseValidator::registerClientScriptValidator();
- }
-
- /**
- * @return string corresponding javascript class name for this this.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveCustomValidator';
- }
-}
-
-/**
- * Custom Validator callback client side options class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveCustomValidatorClientSide extends TCallbackClientSide
-{
- /**
- * @return string javascript code for client-side OnValidate event.
- */
- public function getOnValidate()
- {
- return $this->getOption('OnValidate');
- }
-
- /**
- * Client-side OnValidate validator event is raise before the validators
- * validation functions are called.
- * @param string javascript code for client-side OnValidate event.
- */
- public function setOnValidate($javascript)
- {
- $this->setFunction('OnValidate', $javascript);
- }
-
- /**
- * Client-side OnSuccess event is raise after validation is successfull.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnSuccess event.
- */
- public function setOnValidationSuccess($javascript)
- {
- $this->setFunction('OnValidationSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnSuccess event.
- */
- public function getOnValidationSuccess()
- {
- return $this->getOption('OnValidationSuccess');
- }
-
- /**
- * Client-side OnError event is raised after validation failure.
- * This will override the default client-side validator behaviour.
- * @param string javascript code for client-side OnError event.
- */
- public function setOnValidationError($javascript)
- {
- $this->setFunction('OnValidationError', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnError event.
- */
- public function getOnValidationError()
- {
- return $this->getOption('OnValidationError');
- }
-
- /**
- * @param boolean true to revalidate when the control to validate changes value.
- */
- public function setObserveChanges($value)
- {
- $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return boolean true to observe changes.
- */
- public function getObserveChanges()
- {
- $changes = $this->getOption('ObserveChanges');
- return ($changes===null) ? true : $changes;
- }
-}
+<?php
+/**
+ * TActiveCustomValidator class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TActiveCustomValidator Class
+ *
+ * Performs custom validation using only server-side {@link onServerValidate onServerValidate}
+ * validation event. The client-side uses callbacks to raise
+ * the {@link onServerValidate onServerValidate} event.
+ *
+ * Beware that the {@link onServerValidate onServerValidate} may be
+ * raised when the control to validate on the client side
+ * changes value, that is, the server validation may be called many times.
+ *
+ * After the callback or postback, the {@link onServerValidate onServerValidate}
+ * is raised once more. The {@link getIsCallback IsCallback} property
+ * will be true when validation is made during a callback request.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidator extends TCustomValidator
+ implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * @var boolean true if validation is made during a callback request.
+ */
+ private $_isCallback = false;
+
+ /**
+ * @return boolean true if validation is made during a callback request.
+ */
+ public function getIsCallback()
+ {
+ return $this->_isCallback;
+ }
+
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ $this->getActiveControl()->setClientSide(new TActiveCustomValidatorClientSide);
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client validation function is NOT supported.
+ */
+ public function setClientValidationFunction($value)
+ {
+ throw new TNotSupportedException('tactivecustomvalidator_clientfunction_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface. The {@link onServerValidate
+ * OnServerValidate} event is raised first and then the
+ * {@link onCallback OnCallback} event.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->_isCallback = true;
+ $result = $this->onServerValidate($param->getCallbackParameter());
+ $param->setResponseData($result);
+ $this->onCallback($param);
+ }
+
+ /**
+ * @param boolean whether the value is valid; this method will trigger a clientside update if needed
+ */
+ public function setIsValid($value)
+ {
+ parent::setIsValid($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.updateActiveCustomValidator';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=TBaseValidator::getClientScriptOptions();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Sets the text for the error message. Updates client-side erorr message.
+ * @param string the error message
+ */
+ public function setErrorMessage($value)
+ {
+ parent::setErrorMessage($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $func = 'Prado.Validation.setErrorMessage';
+ $client->callClientFunction($func, array($this, $value));
+ }
+ }
+
+
+ /**
+ * It's mandatory for the EnableClientScript to be activated or the TActiveCustomValidator won't work.
+ * @return boolean whether client-side validation is enabled.
+ */
+ public function getEnableClientScript()
+ {
+ return true;
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ TBaseValidator::registerClientScriptValidator();
+ }
+
+ /**
+ * @return string corresponding javascript class name for this this.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveCustomValidator';
+ }
+}
+
+/**
+ * Custom Validator callback client side options class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveCustomValidatorClientSide extends TCallbackClientSide
+{
+ /**
+ * @return string javascript code for client-side OnValidate event.
+ */
+ public function getOnValidate()
+ {
+ return $this->getOption('OnValidate');
+ }
+
+ /**
+ * Client-side OnValidate validator event is raise before the validators
+ * validation functions are called.
+ * @param string javascript code for client-side OnValidate event.
+ */
+ public function setOnValidate($javascript)
+ {
+ $this->setFunction('OnValidate', $javascript);
+ }
+
+ /**
+ * Client-side OnSuccess event is raise after validation is successfull.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnSuccess event.
+ */
+ public function setOnValidationSuccess($javascript)
+ {
+ $this->setFunction('OnValidationSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnSuccess event.
+ */
+ public function getOnValidationSuccess()
+ {
+ return $this->getOption('OnValidationSuccess');
+ }
+
+ /**
+ * Client-side OnError event is raised after validation failure.
+ * This will override the default client-side validator behaviour.
+ * @param string javascript code for client-side OnError event.
+ */
+ public function setOnValidationError($javascript)
+ {
+ $this->setFunction('OnValidationError', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnError event.
+ */
+ public function getOnValidationError()
+ {
+ return $this->getOption('OnValidationError');
+ }
+
+ /**
+ * @param boolean true to revalidate when the control to validate changes value.
+ */
+ public function setObserveChanges($value)
+ {
+ $this->setOption('ObserveChanges', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return boolean true to observe changes.
+ */
+ public function getObserveChanges()
+ {
+ $changes = $this->getOption('ObserveChanges');
+ return ($changes===null) ? true : $changes;
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TActiveLabel.php b/framework/Web/UI/ActiveControls/TActiveLabel.php
index 32d91cd2..c05b1744 100644
--- a/framework/Web/UI/ActiveControls/TActiveLabel.php
+++ b/framework/Web/UI/ActiveControls/TActiveLabel.php
@@ -80,7 +80,7 @@ class TActiveLabel extends TLabel implements IActiveControl
/**
* Adds attribute id to the renderer.
- * @param THtmlWriter the writer used for the rendering purpose
+ * @param THtmlWriter the writer used for the rendering purpose
*/
protected function addAttributesToRender($writer) {
$writer->addAttribute('id',$this->getClientID());
diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php
index 726dd8ba..144f621e 100644
--- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php
+++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php
@@ -1,401 +1,401 @@
-<?php
-/**
- * TActivePageAdapter, TCallbackErrorHandler and TInvalidCallbackException class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load callback response adapter class.
- */
-Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TActivePageAdapter class.
- *
- * Callback request handler.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePageAdapter extends TControlAdapter
-{
- /**
- * Callback response data header name.
- */
- const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
- /**
- * Callback response client-side action header name.
- */
- const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
- /**
- * Callback error header name.
- */
- const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
- /**
- * Callback page state header name.
- */
- const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
- /**
- * Script list header name.
- */
- const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
- /**
- * Stylesheet list header name.
- */
- const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
- /**
- * Hidden field list header name.
- */
- const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
-
- /**
- * Callback redirect url header name.
- */
- const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
-
- /**
- * @var ICallbackEventHandler callback event handler.
- */
- private $_callbackEventTarget;
- /**
- * @var mixed callback event parameter.
- */
- private $_callbackEventParameter;
- /**
- * @var TCallbackClientScript callback client script handler
- */
- private $_callbackClient;
-
- private $_controlsToRender=array();
-
- /**
- * Constructor, trap errors and exception to let the callback response
- * handle them.
- */
- public function __construct(TPage $control)
- {
- parent::__construct($control);
-
- //TODO: can this be done later?
- $response = $this->getApplication()->getResponse();
- $response->setAdapter(new TCallbackResponseAdapter($response));
-
- $this->trapCallbackErrorsExceptions();
- }
-
- /**
- * Process the callback request.
- * @param THtmlWriter html content writer.
- */
- public function processCallbackEvent($writer)
- {
- Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->raiseCallbackEvent();
- }
-
- /**
- * Register a control for defered render() call.
- * @param TControl control for defered rendering
- * @param THtmlWriter the renderer
- */
- public function registerControlToRender($control,$writer)
- {
- $id = $control->getUniqueID();
- if(!isset($this->_controlsToRender[$id]))
- $this->_controlsToRender[$id] = array($control,$writer);
- }
-
- /**
- * Trap errors and exceptions to be handled by TCallbackErrorHandler.
- */
- protected function trapCallbackErrorsExceptions()
- {
- $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
- }
-
- /**
- * Render the callback response.
- * @param THtmlWriter html content writer.
- */
- public function renderCallbackResponse($writer)
- {
- Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
- $this->renderResponse($writer);
- else
- $this->redirect($url);
- }
-
- /**
- * Redirect url on the client-side using javascript.
- * @param string new url to load.
- */
- protected function redirect($url)
- {
- Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
- //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url);
- }
-
- /**
- * Renders the callback response by adding additional callback data and
- * javascript actions in the header and page state if required.
- * @param THtmlWriter html content writer.
- */
- protected function renderResponse($writer)
- {
- Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
- //renders all the defered render() calls.
- foreach($this->_controlsToRender as $rid => $forRender)
- $forRender[0]->render($forRender[1]);
-
- $response = $this->getResponse();
-
- //send response data in header
- if($response->getHasAdapter())
- {
- $responseData = $response->getAdapter()->getResponseData();
- if($responseData!==null)
- {
- $data = TJavaScript::jsonEncode($responseData);
-
- $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
- //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data);
- }
- }
-
- //sends page state in header
- if(($handler = $this->getCallbackEventTarget()) !== null)
- {
- if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
- {
- $pagestate = $this->getPage()->getClientState();
- $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
- //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate);
- }
- }
-
- //safari must receive at least 1 byte of data.
- $writer->write(" ");
-
- //output the end javascript
- if($this->getPage()->getClientScript()->hasEndScripts())
- {
- $writer = $response->createHtmlWriter();
- $this->getPage()->getClientScript()->renderEndScripts($writer);
- $this->getPage()->getCallbackClient()->evaluateScript($writer);
- }
-
- //output the actions
- $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
- $actions = TJavaScript::jsonEncode($executeJavascript);
- $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
- //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions);
-
-
- $cs = $this->Page->getClientScript();
-
- // collect all stylesheet file references
- $stylesheets = $cs->getStyleSheetUrls();
- if (count($stylesheets)>0)
- $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
-
- // collect all script file references
- $scripts = $cs->getScriptUrls();
- if (count($scripts)>0)
- $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
-
- // collect all hidden field references
- $fields = $cs->getHiddenFields();
- if (count($fields)>0)
- $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
- }
-
- /**
- * Appends data or javascript code to the body content surrounded with delimiters
- */
- private function appendContentPart($response, $delimiter, $data)
- {
- $content = $response->createHtmlWriter();
- $content->getWriter()->setBoundary($delimiter);
- $content->write($data);
- }
-
- /**
- * Trys to find the callback event handler and raise its callback event.
- * @throws TInvalidCallbackException if call back target is not found.
- * @throws TInvalidCallbackException if the requested target does not
- * implement ICallbackEventHandler.
- */
- private function raiseCallbackEvent()
- {
- if(($callbackHandler=$this->getCallbackEventTarget())!==null)
- {
- if($callbackHandler instanceof ICallbackEventHandler)
- {
- $param = $this->getCallbackEventParameter();
- $result = new TCallbackEventParameter($this->getResponse(), $param);
- $callbackHandler->raiseCallbackEvent($result);
- }
- else
- {
- throw new TInvalidCallbackException(
- 'callback_invalid_handler', $callbackHandler->getUniqueID());
- }
- }
- else
- {
- $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- throw new TInvalidCallbackException('callback_invalid_target', $target);
- }
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- if($this->_callbackEventTarget===null)
- {
- $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
- if(!empty($eventTarget))
- $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
- }
- return $this->_callbackEventTarget;
- }
-
- /**
- * Registers a control to raise callback event in the current request.
- * @param TControl control registered to raise callback event.
- */
- public function setCallbackEventTarget(TControl $control)
- {
- $this->_callbackEventTarget=$control;
- }
-
- /**
- * Gets callback parameter. JSON encoding is assumed.
- * @return string postback event parameter
- */
- public function getCallbackEventParameter()
- {
- if($this->_callbackEventParameter===null)
- {
- $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
- if(strlen($param) > 0)
- $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param);
- }
- return $this->_callbackEventParameter;
- }
-
- /**
- * @param mixed postback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->_callbackEventParameter=$value;
- }
-
- /**
- * Gets the callback client script handler. It handlers the javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript callback client handler.
- */
- public function getCallbackClientHandler()
- {
- if($this->_callbackClient===null)
- $this->_callbackClient = new TCallbackClientScript;
- return $this->_callbackClient;
- }
-}
-
-/**
- * TCallbackErrorHandler class.
- *
- * Captures errors and exceptions and send them back during callback response.
- * When the application is in debug mode, the error and exception stack trace
- * are shown. A TJavascriptLogger must be present on the client-side to view
- * the error stack trace.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackErrorHandler extends TErrorHandler
-{
- /**
- * Displays the exceptions to the client-side TJavascriptLogger.
- * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
- * @param Exception exception details.
- */
- protected function displayException($exception)
- {
- if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
- {
- $response = $this->getApplication()->getResponse();
- $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception));
- $response->setStatusCode(500, 'Internal Server Error');
- $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace);
- }
- else
- {
- error_log("Error happened while processing an existing error:\n".$exception->__toString());
- header('HTTP/1.0 500 Internal Server Error', true, 500);
- }
- $this->getApplication()->getResponse()->flush();
- }
-
- /**
- * @param Exception exception details.
- * @return array exception stack trace details.
- */
- private function getExceptionStackTrace($exception)
- {
- $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
- $data['file']=$exception->getFile();
- $data['line']=$exception->getLine();
- $data['trace']=$exception->getTrace();
- if($exception instanceof TPhpErrorException)
- {
- // if PHP exception, we want to show the 2nd stack level context
- // because the 1st stack level is of little use (it's in error handler)
- if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
- {
- $data['file']=$trace[0]['file'];
- $data['line']=$trace[0]['line'];
- }
- }
- $data['type']=get_class($exception);
- $data['message']=$exception->getMessage();
- $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
- $data['time']=@strftime('%Y-%m-%d %H:%M',time());
- return $data;
- }
-}
-
-/**
- * TInvalidCallbackException class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInvalidCallbackException extends TException
-{
-}
-
+<?php
+/**
+ * TActivePageAdapter, TCallbackErrorHandler and TInvalidCallbackException class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load callback response adapter class.
+ */
+Prado::using('System.Web.UI.ActiveControls.TCallbackResponseAdapter');
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientScript');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TActivePageAdapter class.
+ *
+ * Callback request handler.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Gabor Berczi <gabor.berczi@devworx.hu> (lazyload additions & progressive rendering)
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePageAdapter extends TControlAdapter
+{
+ /**
+ * Callback response data header name.
+ */
+ const CALLBACK_DATA_HEADER = 'X-PRADO-DATA';
+ /**
+ * Callback response client-side action header name.
+ */
+ const CALLBACK_ACTION_HEADER = 'X-PRADO-ACTIONS';
+ /**
+ * Callback error header name.
+ */
+ const CALLBACK_ERROR_HEADER = 'X-PRADO-ERROR';
+ /**
+ * Callback page state header name.
+ */
+ const CALLBACK_PAGESTATE_HEADER = 'X-PRADO-PAGESTATE';
+ /**
+ * Script list header name.
+ */
+ const CALLBACK_SCRIPTLIST_HEADER = 'X-PRADO-SCRIPTLIST';
+ /**
+ * Stylesheet list header name.
+ */
+ const CALLBACK_STYLESHEETLIST_HEADER = 'X-PRADO-STYLESHEETLIST';
+ /**
+ * Hidden field list header name.
+ */
+ const CALLBACK_HIDDENFIELDLIST_HEADER = 'X-PRADO-HIDDENFIELDLIST';
+
+ /**
+ * Callback redirect url header name.
+ */
+ const CALLBACK_REDIRECT = 'X-PRADO-REDIRECT';
+
+ /**
+ * @var ICallbackEventHandler callback event handler.
+ */
+ private $_callbackEventTarget;
+ /**
+ * @var mixed callback event parameter.
+ */
+ private $_callbackEventParameter;
+ /**
+ * @var TCallbackClientScript callback client script handler
+ */
+ private $_callbackClient;
+
+ private $_controlsToRender=array();
+
+ /**
+ * Constructor, trap errors and exception to let the callback response
+ * handle them.
+ */
+ public function __construct(TPage $control)
+ {
+ parent::__construct($control);
+
+ //TODO: can this be done later?
+ $response = $this->getApplication()->getResponse();
+ $response->setAdapter(new TCallbackResponseAdapter($response));
+
+ $this->trapCallbackErrorsExceptions();
+ }
+
+ /**
+ * Process the callback request.
+ * @param THtmlWriter html content writer.
+ */
+ public function processCallbackEvent($writer)
+ {
+ Prado::trace("ActivePage raiseCallbackEvent()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->raiseCallbackEvent();
+ }
+
+ /**
+ * Register a control for defered render() call.
+ * @param TControl control for defered rendering
+ * @param THtmlWriter the renderer
+ */
+ public function registerControlToRender($control,$writer)
+ {
+ $id = $control->getUniqueID();
+ if(!isset($this->_controlsToRender[$id]))
+ $this->_controlsToRender[$id] = array($control,$writer);
+ }
+
+ /**
+ * Trap errors and exceptions to be handled by TCallbackErrorHandler.
+ */
+ protected function trapCallbackErrorsExceptions()
+ {
+ $this->getApplication()->setErrorHandler(new TCallbackErrorHandler);
+ }
+
+ /**
+ * Render the callback response.
+ * @param THtmlWriter html content writer.
+ */
+ public function renderCallbackResponse($writer)
+ {
+ Prado::trace("ActivePage renderCallbackResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ if(($url = $this->getResponse()->getAdapter()->getRedirectedUrl())===null)
+ $this->renderResponse($writer);
+ else
+ $this->redirect($url);
+ }
+
+ /**
+ * Redirect url on the client-side using javascript.
+ * @param string new url to load.
+ */
+ protected function redirect($url)
+ {
+ Prado::trace("ActivePage redirect()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ $this->appendContentPart($this->getResponse(), self::CALLBACK_REDIRECT, $url);
+ //$this->getResponse()->appendHeader(self::CALLBACK_REDIRECT.': '.$url);
+ }
+
+ /**
+ * Renders the callback response by adding additional callback data and
+ * javascript actions in the header and page state if required.
+ * @param THtmlWriter html content writer.
+ */
+ protected function renderResponse($writer)
+ {
+ Prado::trace("ActivePage renderResponse()",'System.Web.UI.ActiveControls.TActivePageAdapter');
+ //renders all the defered render() calls.
+ foreach($this->_controlsToRender as $rid => $forRender)
+ $forRender[0]->render($forRender[1]);
+
+ $response = $this->getResponse();
+
+ //send response data in header
+ if($response->getHasAdapter())
+ {
+ $responseData = $response->getAdapter()->getResponseData();
+ if($responseData!==null)
+ {
+ $data = TJavaScript::jsonEncode($responseData);
+
+ $this->appendContentPart($response, self::CALLBACK_DATA_HEADER, $data);
+ //$response->appendHeader(self::CALLBACK_DATA_HEADER.': '.$data);
+ }
+ }
+
+ //sends page state in header
+ if(($handler = $this->getCallbackEventTarget()) !== null)
+ {
+ if($handler->getActiveControl()->getClientSide()->getEnablePageStateUpdate())
+ {
+ $pagestate = $this->getPage()->getClientState();
+ $this->appendContentPart($response, self::CALLBACK_PAGESTATE_HEADER, $pagestate);
+ //$response->appendHeader(self::CALLBACK_PAGESTATE_HEADER.': '.$pagestate);
+ }
+ }
+
+ //safari must receive at least 1 byte of data.
+ $writer->write(" ");
+
+ //output the end javascript
+ if($this->getPage()->getClientScript()->hasEndScripts())
+ {
+ $writer = $response->createHtmlWriter();
+ $this->getPage()->getClientScript()->renderEndScripts($writer);
+ $this->getPage()->getCallbackClient()->evaluateScript($writer);
+ }
+
+ //output the actions
+ $executeJavascript = $this->getCallbackClientHandler()->getClientFunctionsToExecute();
+ $actions = TJavaScript::jsonEncode($executeJavascript);
+ $this->appendContentPart($response, self::CALLBACK_ACTION_HEADER, $actions);
+ //$response->appendHeader(self::CALLBACK_ACTION_HEADER.': '.$actions);
+
+
+ $cs = $this->Page->getClientScript();
+
+ // collect all stylesheet file references
+ $stylesheets = $cs->getStyleSheetUrls();
+ if (count($stylesheets)>0)
+ $this->appendContentPart($response, self::CALLBACK_STYLESHEETLIST_HEADER, TJavaScript::jsonEncode($stylesheets));
+
+ // collect all script file references
+ $scripts = $cs->getScriptUrls();
+ if (count($scripts)>0)
+ $this->appendContentPart($response, self::CALLBACK_SCRIPTLIST_HEADER, TJavaScript::jsonEncode($scripts));
+
+ // collect all hidden field references
+ $fields = $cs->getHiddenFields();
+ if (count($fields)>0)
+ $this->appendContentPart($response, self::CALLBACK_HIDDENFIELDLIST_HEADER, TJavaScript::jsonEncode($fields));
+ }
+
+ /**
+ * Appends data or javascript code to the body content surrounded with delimiters
+ */
+ private function appendContentPart($response, $delimiter, $data)
+ {
+ $content = $response->createHtmlWriter();
+ $content->getWriter()->setBoundary($delimiter);
+ $content->write($data);
+ }
+
+ /**
+ * Trys to find the callback event handler and raise its callback event.
+ * @throws TInvalidCallbackException if call back target is not found.
+ * @throws TInvalidCallbackException if the requested target does not
+ * implement ICallbackEventHandler.
+ */
+ private function raiseCallbackEvent()
+ {
+ if(($callbackHandler=$this->getCallbackEventTarget())!==null)
+ {
+ if($callbackHandler instanceof ICallbackEventHandler)
+ {
+ $param = $this->getCallbackEventParameter();
+ $result = new TCallbackEventParameter($this->getResponse(), $param);
+ $callbackHandler->raiseCallbackEvent($result);
+ }
+ else
+ {
+ throw new TInvalidCallbackException(
+ 'callback_invalid_handler', $callbackHandler->getUniqueID());
+ }
+ }
+ else
+ {
+ $target = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ throw new TInvalidCallbackException('callback_invalid_target', $target);
+ }
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ if($this->_callbackEventTarget===null)
+ {
+ $eventTarget=$this->getRequest()->itemAt(TPage::FIELD_CALLBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_callbackEventTarget=$this->getPage()->findControl($eventTarget);
+ }
+ return $this->_callbackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->_callbackEventTarget=$control;
+ }
+
+ /**
+ * Gets callback parameter. JSON encoding is assumed.
+ * @return string postback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ if($this->_callbackEventParameter===null)
+ {
+ $param = $this->getRequest()->itemAt(TPage::FIELD_CALLBACK_PARAMETER);
+ if(strlen($param) > 0)
+ $this->_callbackEventParameter=TJavaScript::jsonDecode((string)$param);
+ }
+ return $this->_callbackEventParameter;
+ }
+
+ /**
+ * @param mixed postback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->_callbackEventParameter=$value;
+ }
+
+ /**
+ * Gets the callback client script handler. It handlers the javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript callback client handler.
+ */
+ public function getCallbackClientHandler()
+ {
+ if($this->_callbackClient===null)
+ $this->_callbackClient = new TCallbackClientScript;
+ return $this->_callbackClient;
+ }
+}
+
+/**
+ * TCallbackErrorHandler class.
+ *
+ * Captures errors and exceptions and send them back during callback response.
+ * When the application is in debug mode, the error and exception stack trace
+ * are shown. A TJavascriptLogger must be present on the client-side to view
+ * the error stack trace.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackErrorHandler extends TErrorHandler
+{
+ /**
+ * Displays the exceptions to the client-side TJavascriptLogger.
+ * A HTTP 500 status code is sent and the stack trace is sent as JSON encoded.
+ * @param Exception exception details.
+ */
+ protected function displayException($exception)
+ {
+ if($this->getApplication()->getMode()===TApplication::STATE_DEBUG)
+ {
+ $response = $this->getApplication()->getResponse();
+ $trace = TJavaScript::jsonEncode($this->getExceptionStackTrace($exception));
+ $response->setStatusCode(500, 'Internal Server Error');
+ $response->appendHeader(TActivePageAdapter::CALLBACK_ERROR_HEADER.': '.$trace);
+ }
+ else
+ {
+ error_log("Error happened while processing an existing error:\n".$exception->__toString());
+ header('HTTP/1.0 500 Internal Server Error', true, 500);
+ }
+ $this->getApplication()->getResponse()->flush();
+ }
+
+ /**
+ * @param Exception exception details.
+ * @return array exception stack trace details.
+ */
+ private function getExceptionStackTrace($exception)
+ {
+ $data['code']=$exception->getCode() > 0 ? $exception->getCode() : 500;
+ $data['file']=$exception->getFile();
+ $data['line']=$exception->getLine();
+ $data['trace']=$exception->getTrace();
+ if($exception instanceof TPhpErrorException)
+ {
+ // if PHP exception, we want to show the 2nd stack level context
+ // because the 1st stack level is of little use (it's in error handler)
+ if(isset($trace[0]) && isset($trace[0]['file']) && isset($trace[0]['line']))
+ {
+ $data['file']=$trace[0]['file'];
+ $data['line']=$trace[0]['line'];
+ }
+ }
+ $data['type']=get_class($exception);
+ $data['message']=$exception->getMessage();
+ $data['version']=$_SERVER['SERVER_SOFTWARE'].' '.Prado::getVersion();
+ $data['time']=@strftime('%Y-%m-%d %H:%M',time());
+ return $data;
+ }
+}
+
+/**
+ * TInvalidCallbackException class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInvalidCallbackException extends TException
+{
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActivePanel.php b/framework/Web/UI/ActiveControls/TActivePanel.php
index ae1dd09f..1edfa57c 100644
--- a/framework/Web/UI/ActiveControls/TActivePanel.php
+++ b/framework/Web/UI/ActiveControls/TActivePanel.php
@@ -1,100 +1,100 @@
-<?php
-/**
- * TActivePanel file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActivePanel is the TPanel active control counterpart.
- *
- * TActivePanel allows the client-side panel contents to be updated during a
- * callback response using the {@link render} method.
- *
- * Example: Assume $param is an instance of TCallbackEventParameter attached to
- * the OnCallback event of a TCallback with ID "callback1", and
- * "panel1" is the ID of a TActivePanel.
- * <code>
- * function callback1_requested($sender, $param)
- * {
- * $this->panel1->render($param->getNewWriter());
- * }
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActivePanel extends TPanel implements IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveControl standard active control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * Adds attribute id to the renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer) {
- $writer->addAttribute('id',$this->getClientID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders and replaces the panel's content on the client-side.
- * When render() is called before the OnPreRender event, such as when render()
- * is called during a callback event handler, the rendering
- * is defered until OnPreRender event is raised.
- * @param THtmlWriter html writer
- */
- public function render($writer)
- {
- if($this->getHasPreRendered())
- {
- parent::render($writer);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
- }
- else
- {
- $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
- if ($this->getHasControls())
- {
- // If we update a TActivePanel on callback,
- // We shouldn't update all childs, because the whole content will be replaced by
- // the parent
- foreach ($this->findControlsByType('IActiveControl', false) as $control)
- {
- $control->getActiveControl()->setEnableUpdate(false);
- }
- }
- }
- }
-}
-
+<?php
+/**
+ * TActivePanel file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActivePanel is the TPanel active control counterpart.
+ *
+ * TActivePanel allows the client-side panel contents to be updated during a
+ * callback response using the {@link render} method.
+ *
+ * Example: Assume $param is an instance of TCallbackEventParameter attached to
+ * the OnCallback event of a TCallback with ID "callback1", and
+ * "panel1" is the ID of a TActivePanel.
+ * <code>
+ * function callback1_requested($sender, $param)
+ * {
+ * $this->panel1->render($param->getNewWriter());
+ * }
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActivePanel extends TPanel implements IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveControl standard active control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * Adds attribute id to the renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer) {
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders and replaces the panel's content on the client-side.
+ * When render() is called before the OnPreRender event, such as when render()
+ * is called during a callback event handler, the rendering
+ * is defered until OnPreRender event is raised.
+ * @param THtmlWriter html writer
+ */
+ public function render($writer)
+ {
+ if($this->getHasPreRendered())
+ {
+ parent::render($writer);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->getPage()->getCallbackClient()->replaceContent($this,$writer);
+ }
+ else
+ {
+ $this->getPage()->getAdapter()->registerControlToRender($this,$writer);
+ if ($this->getHasControls())
+ {
+ // If we update a TActivePanel on callback,
+ // We shouldn't update all childs, because the whole content will be replaced by
+ // the parent
+ foreach ($this->findControlsByType('IActiveControl', false) as $control)
+ {
+ $control->getActiveControl()->setEnableUpdate(false);
+ }
+ }
+ }
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveRatingList.php b/framework/Web/UI/ActiveControls/TActiveRatingList.php
index 7c878dd8..81f50dd1 100644
--- a/framework/Web/UI/ActiveControls/TActiveRatingList.php
+++ b/framework/Web/UI/ActiveControls/TActiveRatingList.php
@@ -1,133 +1,133 @@
-<?php
-/**
- * TActiveRatingList class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TActiveRatingList Class
- *
- * Displays clickable images that represent a TRadioButtonList
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveListControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- $this->setAdapter(new TActiveListControlAdapter($this));
- $this->setAutoPostBack(true);
- parent::__construct();
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- parent::setReadOnly($value);
- $value = $this->getReadOnly();
- $this->callClientFunction('setReadOnly',$value);
- }
-
- /**
- * @param float rating value, also sets the selected Index
- */
- public function setRating($value)
- {
- parent::setRating($value);
- $value = $this->getRating();
- $this->callClientFunction('setRating',$value);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $code = parent::getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
- }
-
- /**
- * @param string caption text
- */
- public function setCaption($value)
- {
- parent::setCaption($value);
- // if it's an active control, this should not be needed.
- $this->callClientFunction('setCaption',$value);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveRatingList';
- }
-}
-
+<?php
+/**
+ * TActiveRatingList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TActiveRatingList Class
+ *
+ * Displays clickable images that represent a TRadioButtonList
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveRatingList extends TRatingList implements IActiveControl, ICallbackEventHandler
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveListControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ $this->setAdapter(new TActiveListControlAdapter($this));
+ $this->setAutoPostBack(true);
+ parent::__construct();
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ parent::setReadOnly($value);
+ $value = $this->getReadOnly();
+ $this->callClientFunction('setReadOnly',$value);
+ }
+
+ /**
+ * @param float rating value, also sets the selected Index
+ */
+ public function setRating($value)
+ {
+ parent::setRating($value);
+ $value = $this->getRating();
+ $this->callClientFunction('setRating',$value);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = parent::getClientClassName().'.'.$func;
+ $client->callClientFunction($code,array($this,$value));
+ }
+ }
+
+ /**
+ * @param string caption text
+ */
+ public function setCaption($value)
+ {
+ parent::setCaption($value);
+ // if it's an active control, this should not be needed.
+ $this->callClientFunction('setCaption',$value);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveRatingList';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TActiveTextBox.php b/framework/Web/UI/ActiveControls/TActiveTextBox.php
index 1e2fc46f..562f59cd 100644
--- a/framework/Web/UI/ActiveControls/TActiveTextBox.php
+++ b/framework/Web/UI/ActiveControls/TActiveTextBox.php
@@ -1,125 +1,125 @@
-<?php
-/**
- * TActiveTextBox class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TActiveTextBox class.
- *
- * TActiveTextBox allows the {@link setText Text} property of the textbox to
- * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
- * is true, changes to the textbox contents will perform a callback request causing
- * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
- * event.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback control options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Client-side Text property can only be updated after the OnLoad stage.
- * @param string text content for the textbox
- */
- public function setText($value)
- {
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
- $this->getPage()->getCallbackClient()->setValue($this, $value);
- }
-
- /**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TActiveTextBox';
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-}
-
+<?php
+/**
+ * TActiveTextBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TActiveTextBox class.
+ *
+ * TActiveTextBox allows the {@link setText Text} property of the textbox to
+ * be changed during callback. When {@link setAutoPostBack AutoPostBack} property
+ * is true, changes to the textbox contents will perform a callback request causing
+ * {@link onTextChanged OnTextChanged} to be fired first followed by {@link onCallback OnCallback}
+ * event.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TActiveTextBox extends TTextBox implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, by calling this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback control options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Client-side Text property can only be updated after the OnLoad stage.
+ * @param string text content for the textbox
+ */
+ public function setText($value)
+ {
+ parent::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide() && $this->getHasLoadedPostData())
+ $this->getPage()->getCallbackClient()->setValue($this, $value);
+ }
+
+ /**
+ * Raises the callback event. This method is required by {@link
+ * ICallbackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TActiveTextBox';
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php
index 413d5c21..ce648b02 100644
--- a/framework/Web/UI/ActiveControls/TAutoComplete.php
+++ b/framework/Web/UI/ActiveControls/TAutoComplete.php
@@ -1,440 +1,440 @@
-<?php
-/**
- * TAutoComplete class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active text box.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
-
-/**
- * TAutoComplete class.
- *
- * TAutoComplete is a textbox that provides a list of suggestion on
- * the current partial word typed in the textbox. The suggestions are
- * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
- * event. The events of the TActiveText (from which TAutoComplete is extended from)
- * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
- * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
- * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
- * vice versa.
- *
- * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
- * event handler. The partial word to match the suggestion is in the
- * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
- * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
- * method. This sets the datasource for the suggestions repeater, available through
- * the {@link getSuggestions Suggestions} property. Header, footer templates and
- * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
- * property and its sub-properties.
- *
- * The {@link setTextCssClass TextCssClass} property if set is used to find
- * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
- * that contains the actual text for the suggestion selected. That is,
- * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
- * will be used as suggestions.
- *
- * To return the list of suggestions back to the browser, supply a non-empty data source
- * and call databind. For example,
- * <code>
- * function autocomplete_suggestion($sender, $param)
- * {
- * $token = $param->getToken(); //the partial word to match
- * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
- * $sender->dataBind();
- * }
- * </code>
- *
- * The suggestion will be rendered when the {@link dataBind()} method is called
- * <strong>during a callback request</strong>.
- *
- * When an suggestion is selected, that is, when the use has clicked, pressed
- * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
- * event is raised. The
- * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
- * property contains the index of the selected suggestion.
- *
- * TAutoComplete allows multiple suggestions within one textbox with each
- * word or phrase separated by any characters specified in the
- * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
- * and {@link setMinChars MinChars} properties sets the delay and minimum number
- * of characters typed, respectively, before requesting for sugggestions.
- *
- * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
- * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
- *
- * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
- * are considered as text for the suggestion. Text within HTML elements with CSS class name
- * "informal" are ignored as text for suggestions.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoComplete extends TActiveTextBox implements INamingContainer
-{
- /**
- * @var ITemplate template for repeater items
- */
- private $_repeater=null;
- /**
- * @var TPanel result panel holding the suggestion items.
- */
- private $_resultPanel=null;
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function getSeparator()
- {
- return $this->getViewState('tokens', '');
- }
-
- /**
- * @return string word or token separators (delimiters).
- */
- public function setSeparator($value)
- {
- $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
- }
-
- /**
- * @return float maximum delay (in seconds) before requesting a suggestion.
- */
- public function getFrequency()
- {
- return $this->getViewState('frequency', '');
- }
-
- /**
- * @param float maximum delay (in seconds) before requesting a suggestion.
- * Default is 0.4.
- */
- public function setFrequency($value)
- {
- $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
- }
-
- /**
- * @return integer minimum number of characters before requesting a suggestion.
- */
- public function getMinChars()
- {
- return $this->getViewState('minChars','');
- }
-
- /**
- * @param integer minimum number of characters before requesting a suggestion.
- */
- public function setMinChars($value)
- {
- $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
- }
-
- /**
- * @param string Css class name of the element to use for suggestion.
- */
- public function setTextCssClass($value)
- {
- $this->setViewState('TextCssClass', $value);
- }
-
- /**
- * @return string Css class name of the element to use for suggestion.
- */
- public function getTextCssClass()
- {
- return $this->getViewState('TextCssClass');
- }
-
- /**
- * Raises the callback event. This method is overrides the parent implementation.
- * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
- * {@link onTextChanged OnTextChanged} event event and then the
- * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
- * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
- * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- $token = $param->getCallbackParameter();
- if(is_array($token) && count($token) == 2)
- {
- if($token[1] === '__TAutoComplete_onSuggest__')
- {
- $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
- $this->onSuggest($parameter);
- }
- else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
- {
- $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
- $this->onSuggestionSelected($parameter);
- }
- }
- else if($this->getAutoPostBack())
- parent::raiseCallbackEvent($param);
- }
-
- /**
- * This method is invoked when an autocomplete suggestion is requested.
- * The method raises 'OnSuggest' event. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onSuggest($param)
- {
- $this->raiseEvent('OnSuggest', $this, $param);
- }
-
- /**
- * This method is invoked when an autocomplete suggestion is selected.
- * The method raises 'OnSuggestionSelected' event. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onSuggestionSelected($param)
- {
- $this->raiseEvent('OnSuggestionSelected', $this, $param);
- }
-
- /**
- * @param array data source for suggestions.
- */
- public function setDataSource($data)
- {
- $this->getSuggestions()->setDataSource($data);
- }
-
- /**
- * Overrides parent implementation. Callback {@link renderSuggestions()} when
- * page's IsCallback property is true.
- */
- public function dataBind()
- {
- parent::dataBind();
- if($this->getPage()->getIsCallback())
- $this->renderSuggestions($this->getResponse()->createHtmlWriter());
- }
-
- /**
- * @return TPanel suggestion results panel.
- */
- public function getResultPanel()
- {
- if($this->_resultPanel===null)
- $this->_resultPanel = $this->createResultPanel();
- return $this->_resultPanel;
- }
-
- /**
- * @return TPanel new instance of result panel. Default uses TPanel.
- */
- protected function createResultPanel()
- {
- $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
- $this->getControls()->add($panel);
- $panel->setID('result');
- return $panel;
- }
-
- /**
- * @return TRepeater suggestion list repeater
- */
- public function getSuggestions()
- {
- if($this->_repeater===null)
- $this->_repeater = $this->createRepeater();
- return $this->_repeater;
- }
-
- /**
- * @return TRepeater new instance of TRepater to render the list of suggestions.
- */
- protected function createRepeater()
- {
- $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
- $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
- $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
- $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
- $this->getControls()->add($repeater);
- return $repeater;
- }
-
- /**
- * Renders the end tag and registers javascript effects library.
- */
- public function renderEndTag($writer)
- {
- $this->getPage()->getClientScript()->registerPradoScript('effects');
- parent::renderEndTag($writer);
- $this->renderResultPanel($writer);
- }
-
- /**
- * Renders the result panel.
- * @param THtmlWriter the renderer.
- */
- protected function renderResultPanel($writer)
- {
- $this->getResultPanel()->render($writer);
- }
-
- /**
- * Renders the suggestions during a callback respones.
- * @param THtmlWriter the renderer.
- */
- public function renderCallback($writer)
- {
- $this->renderSuggestions($writer);
- }
-
- /**
- * Renders the suggestions repeater.
- * @param THtmlWriter the renderer.
- */
- public function renderSuggestions($writer)
- {
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $this->getSuggestions()->render($writer);
- $boundary = $writer->getWriter()->getBoundary();
- $this->getResponse()->getAdapter()->setResponseData($boundary);
- }
- }
-
- /**
- * @return array list of callback options.
- */
- protected function getPostBackOptions()
- {
- //disallow page state update ?
- //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
- $options = array();
- if(strlen($string = $this->getSeparator()))
- {
- $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
- $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
- $options['tokens'] = $token;
- }
- if($this->getAutoPostBack())
- {
- $options = array_merge($options,parent::getPostBackOptions());
- $options['AutoPostBack'] = true;
- }
- if(strlen($select = $this->getTextCssClass()))
- $options['select'] = $select;
- $options['ResultPanel'] = $this->getResultPanel()->getClientID();
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- if(($minchars=$this->getMinChars())!=='')
- $options['minChars'] = $minchars;
- if(($frequency=$this->getFrequency())!=='')
- $options['frequency'] = $frequency;
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- return $options;
- }
-
- /**
- * Override parent implementation, no javascript is rendered here instead
- * the javascript required for active control is registered in {@link addAttributesToRender}.
- */
- protected function renderClientControlScript($writer)
- {
- }
-
- /**
- * @return string corresponding javascript class name for this TActiveButton.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TAutoComplete';
- }
-}
-
-/**
- * TAutCompleteEventParameter contains the {@link getToken Token} requested by
- * the user for a partial match of the suggestions.
- *
- * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
- * suggestion selected by the user, -1 if not suggestion is selected.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteEventParameter extends TCallbackEventParameter
-{
- private $_selectedIndex=-1;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter, $index=-1)
- {
- parent::__construct($response, $parameter);
- $this->_selectedIndex=$index;
- }
-
- /**
- * @return int selected suggestion zero-based index, -1 if not selected.
- */
- public function getSelectedIndex()
- {
- return $this->_selectedIndex;
- }
-
- /**
- * @return string token for matching a list of suggestions.
- */
- public function getToken()
- {
- return $this->getCallbackParameter();
- }
-}
-
-/**
- * TAutoCompleteTemplate class.
- *
- * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
- * item template.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TAutoCompleteTemplate extends TComponent implements ITemplate
-{
- private $_template;
-
- public function __construct($template)
- {
- $this->_template = $template;
- }
- /**
- * Instantiates the template.
- * It creates a {@link TDataList} control.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $parent->getControls()->add($this->_template);
- }
-}
-
+<?php
+/**
+ * TAutoComplete class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active text box.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+Prado::using('System.Web.UI.ActiveControls.TCallbackEventParameter');
+
+/**
+ * TAutoComplete class.
+ *
+ * TAutoComplete is a textbox that provides a list of suggestion on
+ * the current partial word typed in the textbox. The suggestions are
+ * requested using callbacks, and raises the {@link onSuggestion OnSuggestion}
+ * event. The events of the TActiveText (from which TAutoComplete is extended from)
+ * and {@link onSuggestion OnSuggestion} are mutually exculsive. That is,
+ * if {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback}
+ * events are raise, then {@link onSuggestion OnSuggestion} will not be raise, and
+ * vice versa.
+ *
+ * The list of suggestions should be set in the {@link onSuggestion OnSuggestion}
+ * event handler. The partial word to match the suggestion is in the
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property. The datasource of the TAutoComplete must be set using {@link setDataSource}
+ * method. This sets the datasource for the suggestions repeater, available through
+ * the {@link getSuggestions Suggestions} property. Header, footer templates and
+ * other properties of the repeater can be access via the {@link getSuggestions Suggestions}
+ * property and its sub-properties.
+ *
+ * The {@link setTextCssClass TextCssClass} property if set is used to find
+ * the element within the Suggestions.ItemTemplate and Suggestions.AlternatingItemTemplate
+ * that contains the actual text for the suggestion selected. That is,
+ * only text inside elements with CSS class name equal to {@link setTextCssClass TextCssClass}
+ * will be used as suggestions.
+ *
+ * To return the list of suggestions back to the browser, supply a non-empty data source
+ * and call databind. For example,
+ * <code>
+ * function autocomplete_suggestion($sender, $param)
+ * {
+ * $token = $param->getToken(); //the partial word to match
+ * $sender->setDataSource($this->getSuggestionsFor($token)); //set suggestions
+ * $sender->dataBind();
+ * }
+ * </code>
+ *
+ * The suggestion will be rendered when the {@link dataBind()} method is called
+ * <strong>during a callback request</strong>.
+ *
+ * When an suggestion is selected, that is, when the use has clicked, pressed
+ * the "Enter" key, or pressed the "Tab" key, the {@link onSuggestionSelected OnSuggestionSelected}
+ * event is raised. The
+ * {@link TCallbackEventParameter::getCallbackParameter TCallbackEventParameter::CallbackParameter}
+ * property contains the index of the selected suggestion.
+ *
+ * TAutoComplete allows multiple suggestions within one textbox with each
+ * word or phrase separated by any characters specified in the
+ * {@link setSeparator Separator} property. The {@link setFrequency Frequency}
+ * and {@link setMinChars MinChars} properties sets the delay and minimum number
+ * of characters typed, respectively, before requesting for sugggestions.
+ *
+ * Use {@link onTextChange OnTextChange} and/or {@link onCallback OnCallback} events
+ * to handle post backs due to {@link setAutoPostBack AutoPostBack}.
+ *
+ * In the {@link getSuggestions Suggestions} TRepater item template, all HTML text elements
+ * are considered as text for the suggestion. Text within HTML elements with CSS class name
+ * "informal" are ignored as text for suggestions.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoComplete extends TActiveTextBox implements INamingContainer
+{
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_repeater=null;
+ /**
+ * @var TPanel result panel holding the suggestion items.
+ */
+ private $_resultPanel=null;
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function getSeparator()
+ {
+ return $this->getViewState('tokens', '');
+ }
+
+ /**
+ * @return string word or token separators (delimiters).
+ */
+ public function setSeparator($value)
+ {
+ $this->setViewState('tokens', TPropertyValue::ensureString($value), '');
+ }
+
+ /**
+ * @return float maximum delay (in seconds) before requesting a suggestion.
+ */
+ public function getFrequency()
+ {
+ return $this->getViewState('frequency', '');
+ }
+
+ /**
+ * @param float maximum delay (in seconds) before requesting a suggestion.
+ * Default is 0.4.
+ */
+ public function setFrequency($value)
+ {
+ $this->setViewState('frequency', TPropertyValue::ensureFloat($value),'');
+ }
+
+ /**
+ * @return integer minimum number of characters before requesting a suggestion.
+ */
+ public function getMinChars()
+ {
+ return $this->getViewState('minChars','');
+ }
+
+ /**
+ * @param integer minimum number of characters before requesting a suggestion.
+ */
+ public function setMinChars($value)
+ {
+ $this->setViewState('minChars', TPropertyValue::ensureInteger($value), '');
+ }
+
+ /**
+ * @param string Css class name of the element to use for suggestion.
+ */
+ public function setTextCssClass($value)
+ {
+ $this->setViewState('TextCssClass', $value);
+ }
+
+ /**
+ * @return string Css class name of the element to use for suggestion.
+ */
+ public function getTextCssClass()
+ {
+ return $this->getViewState('TextCssClass');
+ }
+
+ /**
+ * Raises the callback event. This method is overrides the parent implementation.
+ * If {@link setAutoPostBack AutoPostBack} is enabled it will raise
+ * {@link onTextChanged OnTextChanged} event event and then the
+ * {@link onCallback OnCallback} event. The {@link onSuggest OnSuggest} event is
+ * raise if the request is to find sugggestions, the {@link onTextChanged OnTextChanged}
+ * and {@link onCallback OnCallback} events are <b>NOT</b> raised.
+ * This method is mainly used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ $token = $param->getCallbackParameter();
+ if(is_array($token) && count($token) == 2)
+ {
+ if($token[1] === '__TAutoComplete_onSuggest__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), $token[0]);
+ $this->onSuggest($parameter);
+ }
+ else if($token[1] === '__TAutoComplete_onSuggestionSelected__')
+ {
+ $parameter = new TAutoCompleteEventParameter($this->getResponse(), null, $token[0]);
+ $this->onSuggestionSelected($parameter);
+ }
+ }
+ else if($this->getAutoPostBack())
+ parent::raiseCallbackEvent($param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is requested.
+ * The method raises 'OnSuggest' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggest($param)
+ {
+ $this->raiseEvent('OnSuggest', $this, $param);
+ }
+
+ /**
+ * This method is invoked when an autocomplete suggestion is selected.
+ * The method raises 'OnSuggestionSelected' event. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onSuggestionSelected($param)
+ {
+ $this->raiseEvent('OnSuggestionSelected', $this, $param);
+ }
+
+ /**
+ * @param array data source for suggestions.
+ */
+ public function setDataSource($data)
+ {
+ $this->getSuggestions()->setDataSource($data);
+ }
+
+ /**
+ * Overrides parent implementation. Callback {@link renderSuggestions()} when
+ * page's IsCallback property is true.
+ */
+ public function dataBind()
+ {
+ parent::dataBind();
+ if($this->getPage()->getIsCallback())
+ $this->renderSuggestions($this->getResponse()->createHtmlWriter());
+ }
+
+ /**
+ * @return TPanel suggestion results panel.
+ */
+ public function getResultPanel()
+ {
+ if($this->_resultPanel===null)
+ $this->_resultPanel = $this->createResultPanel();
+ return $this->_resultPanel;
+ }
+
+ /**
+ * @return TPanel new instance of result panel. Default uses TPanel.
+ */
+ protected function createResultPanel()
+ {
+ $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel');
+ $this->getControls()->add($panel);
+ $panel->setID('result');
+ return $panel;
+ }
+
+ /**
+ * @return TRepeater suggestion list repeater
+ */
+ public function getSuggestions()
+ {
+ if($this->_repeater===null)
+ $this->_repeater = $this->createRepeater();
+ return $this->_repeater;
+ }
+
+ /**
+ * @return TRepeater new instance of TRepater to render the list of suggestions.
+ */
+ protected function createRepeater()
+ {
+ $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater');
+ $repeater->setHeaderTemplate(new TAutoCompleteTemplate('<ul>'));
+ $repeater->setFooterTemplate(new TAutoCompleteTemplate('</ul>'));
+ $repeater->setItemTemplate(new TTemplate('<li><%# $this->DataItem %></li>',null));
+ $this->getControls()->add($repeater);
+ return $repeater;
+ }
+
+ /**
+ * Renders the end tag and registers javascript effects library.
+ */
+ public function renderEndTag($writer)
+ {
+ $this->getPage()->getClientScript()->registerPradoScript('effects');
+ parent::renderEndTag($writer);
+ $this->renderResultPanel($writer);
+ }
+
+ /**
+ * Renders the result panel.
+ * @param THtmlWriter the renderer.
+ */
+ protected function renderResultPanel($writer)
+ {
+ $this->getResultPanel()->render($writer);
+ }
+
+ /**
+ * Renders the suggestions during a callback respones.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderCallback($writer)
+ {
+ $this->renderSuggestions($writer);
+ }
+
+ /**
+ * Renders the suggestions repeater.
+ * @param THtmlWriter the renderer.
+ */
+ public function renderSuggestions($writer)
+ {
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->getSuggestions()->render($writer);
+ $boundary = $writer->getWriter()->getBoundary();
+ $this->getResponse()->getAdapter()->setResponseData($boundary);
+ }
+ }
+
+ /**
+ * @return array list of callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ //disallow page state update ?
+ //$this->getActiveControl()->getClientSide()->setEnablePageStateUpdate(false);
+ $options = array();
+ if(strlen($string = $this->getSeparator()))
+ {
+ $string = strtr($string,array('\t'=>"\t",'\n'=>"\n",'\r'=>"\r"));
+ $token = preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY);
+ $options['tokens'] = $token;
+ }
+ if($this->getAutoPostBack())
+ {
+ $options = array_merge($options,parent::getPostBackOptions());
+ $options['AutoPostBack'] = true;
+ }
+ if(strlen($select = $this->getTextCssClass()))
+ $options['select'] = $select;
+ $options['ResultPanel'] = $this->getResultPanel()->getClientID();
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ if(($minchars=$this->getMinChars())!=='')
+ $options['minChars'] = $minchars;
+ if(($frequency=$this->getFrequency())!=='')
+ $options['frequency'] = $frequency;
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ return $options;
+ }
+
+ /**
+ * Override parent implementation, no javascript is rendered here instead
+ * the javascript required for active control is registered in {@link addAttributesToRender}.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TActiveButton.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAutoComplete';
+ }
+}
+
+/**
+ * TAutCompleteEventParameter contains the {@link getToken Token} requested by
+ * the user for a partial match of the suggestions.
+ *
+ * The {@link getSelectedIndex SelectedIndex} is a zero-based index of the
+ * suggestion selected by the user, -1 if not suggestion is selected.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteEventParameter extends TCallbackEventParameter
+{
+ private $_selectedIndex=-1;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter, $index=-1)
+ {
+ parent::__construct($response, $parameter);
+ $this->_selectedIndex=$index;
+ }
+
+ /**
+ * @return int selected suggestion zero-based index, -1 if not selected.
+ */
+ public function getSelectedIndex()
+ {
+ return $this->_selectedIndex;
+ }
+
+ /**
+ * @return string token for matching a list of suggestions.
+ */
+ public function getToken()
+ {
+ return $this->getCallbackParameter();
+ }
+}
+
+/**
+ * TAutoCompleteTemplate class.
+ *
+ * TAutoCompleteTemplate is the default template for TAutoCompleteTemplate
+ * item template.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TAutoCompleteTemplate extends TComponent implements ITemplate
+{
+ private $_template;
+
+ public function __construct($template)
+ {
+ $this->_template = $template;
+ }
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $parent->getControls()->add($this->_template);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TBaseActiveControl.php b/framework/Web/UI/ActiveControls/TBaseActiveControl.php
index d3391b71..c412a2e2 100644
--- a/framework/Web/UI/ActiveControls/TBaseActiveControl.php
+++ b/framework/Web/UI/ActiveControls/TBaseActiveControl.php
@@ -1,392 +1,392 @@
-<?php
-/**
- * TBaseActiveControl and TBaseActiveCallbackControl class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
-
-/**
- * TBaseActiveControl class provided additional basic property for every
- * active control. An instance of TBaseActiveControl or its decendent
- * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
- * method.
- *
- * The {@link setEnableUpdate EnableUpdate} property determines wether the active
- * control is allowed to update the contents of the client-side when the callback
- * response returns.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveControl extends TComponent
-{
- /**
- * @var TMap map of active control options.
- */
- private $_options;
- /**
- * @var TControl attached control.
- */
- private $_control;
-
- /**
- * Constructor. Attach a base active control to an active control instance.
- * @param TControl active control
- */
- public function __construct($control)
- {
- $this->_control = $control;
- $this->_options = new TMap;
- }
-
- /**
- * Sets a named options with a value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed new value.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function setOption($name,$value,$default=null)
- {
- $value = ($value===null) ? $default : $value;
- if($value!==null)
- $this->_options->add($name,$value);
- }
-
- /**
- * Gets an option named value. Options are used to store and retrive
- * named values for the base active controls.
- * @param string option name.
- * @param mixed default value.
- * @return mixed options value.
- */
- protected function getOption($name,$default=null)
- {
- $item = $this->_options->itemAt($name);
- return ($item===null) ? $default : $item;
- }
-
- /**
- * @return TMap active control options
- */
- protected function getOptions()
- {
- return $this->_options;
- }
-
- /**
- * @return TPage the page containing the attached control.
- */
- protected function getPage()
- {
- return $this->_control->getPage();
- }
-
- /**
- * @return TControl the attached control.
- */
- protected function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @param boolean true to allow fine grain callback updates.
- */
- public function setEnableUpdate($value)
- {
- $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true to allow fine grain callback updates.
- */
- public function getEnableUpdate()
- {
- return $this->getOption('EnableUpdate', true);
- }
-
- /**
- * Returns true if callback response is allowed to update the browser contents.
- * Is is true if the control is initilized, and is a callback request and
- * the {@link setEnableUpdate EnableUpdate} property is true and
- * the page is not loading post data.
- * @return boolean true if the callback response is allowed update
- * client-side contents.
- */
- public function canUpdateClientSide($bDontRequireVisibility=false)
- {
- return $this->getControl()->getHasChildInitialized()
- && $this->getPage()->getIsLoadingPostData() == false
- && $this->getPage()->getIsCallback()
- && $this->getEnableUpdate()
- && ($bDontRequireVisibility || $this->getControl()->getVisible());
- }
-}
-
-/**
- * TBaseActiveCallbackControl is a common set of options and functionality for
- * active controls that can perform callback requests.
- *
- * The properties of TBaseActiveCallbackControl can be accessed and changed from
- * each individual active controls' {@link getActiveControl ActiveControl}
- * property.
- *
- * The following example sets the validation group property of a TCallback component.
- * <code>
- * <com:TCallback ActiveControl.ValidationGroup="group1" ... />
- * </code>
- *
- * Additional client-side options and events can be set using the
- * {@link getClientSide ClientSide} property. The following example shows
- * an alert box when a TCallback component response returns successfully.
- * <code>
- * <com:TCallback ActiveControl.ClientSide.OnSuccess="alert('ok!')" ... />
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TBaseActiveCallbackControl extends TBaseActiveControl
-{
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g. <com:TCallback ActiveControl.ClientSide.OnSuccess="..." />
- * See {@link TCallbackClientSide} for details on the properties of ClientSide.
- * @return TCallbackClientSide client-side callback options.
- */
- public function getClientSide()
- {
- if(($client = $this->getOption('ClientSide'))===null)
- {
- $client = $this->createClientSide();
- $this->setOption('ClientSide', $client);
- }
- return $client;
- }
-
- /**
- * Sets the client side options. Can only be set when client side is null.
- * @param TCallbackClientSide client side options.
- */
- public function setClientSide($client)
- {
- if( $this->getOption('ClientSide')===null)
- $this->setOption('ClientSide', $client);
- else
- throw new TConfigurationException(
- 'active_controls_client_side_exists', $this->getControl()->getID());
- }
-
- /**
- * @return TCallbackClientSide callback client-side options.
- */
- protected function createClientSide()
- {
- return new TCallbackClientSide;
- }
-
- /**
- * Sets default callback options. Takes the ID of a TCallbackOptions
- * component to duplicate the client-side
- * options for this control. The {@link getClientSide ClientSide}
- * subproperties takes precedence over the CallbackOptions property.
- * @param string ID of a TCallbackOptions control from which ClientSide
- * options are cloned.
- */
- public function setCallbackOptions($value)
- {
- $this->setOption('CallbackOptions', $value, '');
- }
-
- /**
- * @return string ID of a TCallbackOptions control from which ClientSide
- * options are duplicated.
- */
- public function getCallbackOptions()
- {
- return $this->getOption('CallbackOptions', '');
- }
-
- /**
- * Returns an array of default callback client-side options. The default options
- * are obtained from the client-side options of a TCallbackOptions control with
- * ID specified by {@link setCallbackOptions CallbackOptions}.
- * @return array list of default callback client-side options.
- */
- protected function getDefaultClientSideOptions()
- {
- if(($id=$this->getCallbackOptions())!=='')
- {
- if(($pos=strrpos($id,'.'))!==false)
- {
- $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
- $newid=substr($id,$pos+1);
- if ($control!==null)
- $control=$control->$newid;
- }
- else
- {
- $control=$this->getControl()->findControl($id);
- }
-
- if($control instanceof TCallbackOptions)
- return $control->getClientSide()->getOptions()->toArray();
- else
- throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
- }
-
- return array();
- }
-
- /**
- * @return boolean whether callback event trigger by this button will cause
- * input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getOption('CausesValidation',true);
- }
-
- /**
- * @param boolean whether callback event trigger by this button will cause
- * input validation
- */
- public function setCausesValidation($value)
- {
- $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation
- * upon callback
- */
- public function getValidationGroup()
- {
- return $this->getOption('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation
- * upon callback
- */
- public function setValidationGroup($value)
- {
- $this->setOption('ValidationGroup',$value,'');
- }
-
- /**
- * @return boolean whether to perform validation if the callback is
- * requested.
- */
- public function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param mixed callback parameter value.
- */
- public function setCallbackParameter($value)
- {
- $this->setOption('CallbackParameter', $value, '');
- }
-
- /**
- * @return mixed callback parameter value.
- */
- public function getCallbackParameter()
- {
- return $this->getOption('CallbackParameter', '');
- }
-
-
- /**
- * @return array list of callback javascript options.
- */
- protected function getClientSideOptions()
- {
- $default = $this->getDefaultClientSideOptions();
- $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
- $validate = $this->getCausesValidation();
- $options['CausesValidation']= $validate ? '' : false;
- $options['ValidationGroup']=$this->getValidationGroup();
- $options['CallbackParameter'] = $this->getCallbackParameter();
- return $options;
- }
-
- /**
- * Registers the callback control javascript code. Client-side options are
- * merged and passed to the javascript code. This method should be called by
- * Active component developers wanting to register the javascript to initialize
- * the active component with additional options offered by the
- * {@link getClientSide ClientSide} property.
- * @param string client side javascript class name.
- * @param array additional callback options.
- */
- public function registerCallbackClientScript($class,$options=null)
- {
- $cs = $this->getPage()->getClientScript();
- if(is_array($options))
- $options = array_merge($this->getClientSideOptions(),$options);
- else
- $options = $this->getClientSideOptions();
-
- //remove true as default to save bytes
- if($options['CausesValidation']===true)
- $options['CausesValidation']='';
- $cs->registerCallbackControl($class, $options);
- }
-
- /**
- * Returns the javascript callback request instance. To invoke a callback
- * request for this control call the <tt>dispatch()</tt> method on the
- * request instance. Example code in javascript
- * <code>
- * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
- * request.setParameter('hello');
- * request.dispatch(); //make the callback request.
- * </code>
- *
- * Alternatively,
- * <code>
- * //dispatches immediately
- * Prado.Callback("<%= $this->mycallback->UniqueID %>",
- * $this->mycallback->ActiveControl->JsCallbackOptions);
- * </code>
- * @return string javascript client-side callback request object (javascript
- * code)
- */
- public function getJavascript()
- {
- $client = $this->getPage()->getClientScript();
- return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions());
- }
-
- /**
- * @param string callback requestion options as javascript code.
- */
- public function getJsCallbackOptions()
- {
- return TJavaScript::encode($this->getClientSideOptions());
- }
-}
-
+<?php
+/**
+ * TBaseActiveControl and TBaseActiveCallbackControl class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallbackClientSide');
+
+/**
+ * TBaseActiveControl class provided additional basic property for every
+ * active control. An instance of TBaseActiveControl or its decendent
+ * TBaseActiveCallbackControl is created by {@link TActiveControlAdapter::getBaseActiveControl()}
+ * method.
+ *
+ * The {@link setEnableUpdate EnableUpdate} property determines wether the active
+ * control is allowed to update the contents of the client-side when the callback
+ * response returns.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveControl extends TComponent
+{
+ /**
+ * @var TMap map of active control options.
+ */
+ private $_options;
+ /**
+ * @var TControl attached control.
+ */
+ private $_control;
+
+ /**
+ * Constructor. Attach a base active control to an active control instance.
+ * @param TControl active control
+ */
+ public function __construct($control)
+ {
+ $this->_control = $control;
+ $this->_options = new TMap;
+ }
+
+ /**
+ * Sets a named options with a value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed new value.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function setOption($name,$value,$default=null)
+ {
+ $value = ($value===null) ? $default : $value;
+ if($value!==null)
+ $this->_options->add($name,$value);
+ }
+
+ /**
+ * Gets an option named value. Options are used to store and retrive
+ * named values for the base active controls.
+ * @param string option name.
+ * @param mixed default value.
+ * @return mixed options value.
+ */
+ protected function getOption($name,$default=null)
+ {
+ $item = $this->_options->itemAt($name);
+ return ($item===null) ? $default : $item;
+ }
+
+ /**
+ * @return TMap active control options
+ */
+ protected function getOptions()
+ {
+ return $this->_options;
+ }
+
+ /**
+ * @return TPage the page containing the attached control.
+ */
+ protected function getPage()
+ {
+ return $this->_control->getPage();
+ }
+
+ /**
+ * @return TControl the attached control.
+ */
+ protected function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @param boolean true to allow fine grain callback updates.
+ */
+ public function setEnableUpdate($value)
+ {
+ $this->setOption('EnableUpdate', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true to allow fine grain callback updates.
+ */
+ public function getEnableUpdate()
+ {
+ return $this->getOption('EnableUpdate', true);
+ }
+
+ /**
+ * Returns true if callback response is allowed to update the browser contents.
+ * Is is true if the control is initilized, and is a callback request and
+ * the {@link setEnableUpdate EnableUpdate} property is true and
+ * the page is not loading post data.
+ * @return boolean true if the callback response is allowed update
+ * client-side contents.
+ */
+ public function canUpdateClientSide($bDontRequireVisibility=false)
+ {
+ return $this->getControl()->getHasChildInitialized()
+ && $this->getPage()->getIsLoadingPostData() == false
+ && $this->getPage()->getIsCallback()
+ && $this->getEnableUpdate()
+ && ($bDontRequireVisibility || $this->getControl()->getVisible());
+ }
+}
+
+/**
+ * TBaseActiveCallbackControl is a common set of options and functionality for
+ * active controls that can perform callback requests.
+ *
+ * The properties of TBaseActiveCallbackControl can be accessed and changed from
+ * each individual active controls' {@link getActiveControl ActiveControl}
+ * property.
+ *
+ * The following example sets the validation group property of a TCallback component.
+ * <code>
+ * <com:TCallback ActiveControl.ValidationGroup="group1" ... />
+ * </code>
+ *
+ * Additional client-side options and events can be set using the
+ * {@link getClientSide ClientSide} property. The following example shows
+ * an alert box when a TCallback component response returns successfully.
+ * <code>
+ * <com:TCallback ActiveControl.ClientSide.OnSuccess="alert('ok!')" ... />
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TBaseActiveCallbackControl extends TBaseActiveControl
+{
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g. <com:TCallback ActiveControl.ClientSide.OnSuccess="..." />
+ * See {@link TCallbackClientSide} for details on the properties of ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if(($client = $this->getOption('ClientSide'))===null)
+ {
+ $client = $this->createClientSide();
+ $this->setOption('ClientSide', $client);
+ }
+ return $client;
+ }
+
+ /**
+ * Sets the client side options. Can only be set when client side is null.
+ * @param TCallbackClientSide client side options.
+ */
+ public function setClientSide($client)
+ {
+ if( $this->getOption('ClientSide')===null)
+ $this->setOption('ClientSide', $client);
+ else
+ throw new TConfigurationException(
+ 'active_controls_client_side_exists', $this->getControl()->getID());
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return new TCallbackClientSide;
+ }
+
+ /**
+ * Sets default callback options. Takes the ID of a TCallbackOptions
+ * component to duplicate the client-side
+ * options for this control. The {@link getClientSide ClientSide}
+ * subproperties takes precedence over the CallbackOptions property.
+ * @param string ID of a TCallbackOptions control from which ClientSide
+ * options are cloned.
+ */
+ public function setCallbackOptions($value)
+ {
+ $this->setOption('CallbackOptions', $value, '');
+ }
+
+ /**
+ * @return string ID of a TCallbackOptions control from which ClientSide
+ * options are duplicated.
+ */
+ public function getCallbackOptions()
+ {
+ return $this->getOption('CallbackOptions', '');
+ }
+
+ /**
+ * Returns an array of default callback client-side options. The default options
+ * are obtained from the client-side options of a TCallbackOptions control with
+ * ID specified by {@link setCallbackOptions CallbackOptions}.
+ * @return array list of default callback client-side options.
+ */
+ protected function getDefaultClientSideOptions()
+ {
+ if(($id=$this->getCallbackOptions())!=='')
+ {
+ if(($pos=strrpos($id,'.'))!==false)
+ {
+ $control=$this->getControl()->getSubProperty(substr($id,0,$pos));
+ $newid=substr($id,$pos+1);
+ if ($control!==null)
+ $control=$control->$newid;
+ }
+ else
+ {
+ $control=$this->getControl()->findControl($id);
+ }
+
+ if($control instanceof TCallbackOptions)
+ return $control->getClientSide()->getOptions()->toArray();
+ else
+ throw new TConfigurationException('callback_invalid_callback_options', $this->getControl()->getID(), $id);
+ }
+
+ return array();
+ }
+
+ /**
+ * @return boolean whether callback event trigger by this button will cause
+ * input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getOption('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether callback event trigger by this button will cause
+ * input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setOption('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getOption('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation
+ * upon callback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setOption('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether to perform validation if the callback is
+ * requested.
+ */
+ public function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param mixed callback parameter value.
+ */
+ public function setCallbackParameter($value)
+ {
+ $this->setOption('CallbackParameter', $value, '');
+ }
+
+ /**
+ * @return mixed callback parameter value.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->getOption('CallbackParameter', '');
+ }
+
+
+ /**
+ * @return array list of callback javascript options.
+ */
+ protected function getClientSideOptions()
+ {
+ $default = $this->getDefaultClientSideOptions();
+ $options = array_merge($default,$this->getClientSide()->getOptions()->toArray());
+ $validate = $this->getCausesValidation();
+ $options['CausesValidation']= $validate ? '' : false;
+ $options['ValidationGroup']=$this->getValidationGroup();
+ $options['CallbackParameter'] = $this->getCallbackParameter();
+ return $options;
+ }
+
+ /**
+ * Registers the callback control javascript code. Client-side options are
+ * merged and passed to the javascript code. This method should be called by
+ * Active component developers wanting to register the javascript to initialize
+ * the active component with additional options offered by the
+ * {@link getClientSide ClientSide} property.
+ * @param string client side javascript class name.
+ * @param array additional callback options.
+ */
+ public function registerCallbackClientScript($class,$options=null)
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(is_array($options))
+ $options = array_merge($this->getClientSideOptions(),$options);
+ else
+ $options = $this->getClientSideOptions();
+
+ //remove true as default to save bytes
+ if($options['CausesValidation']===true)
+ $options['CausesValidation']='';
+ $cs->registerCallbackControl($class, $options);
+ }
+
+ /**
+ * Returns the javascript callback request instance. To invoke a callback
+ * request for this control call the <tt>dispatch()</tt> method on the
+ * request instance. Example code in javascript
+ * <code>
+ * var request = <%= $this->mycallback->ActiveControl->Javascript %>;
+ * request.setParameter('hello');
+ * request.dispatch(); //make the callback request.
+ * </code>
+ *
+ * Alternatively,
+ * <code>
+ * //dispatches immediately
+ * Prado.Callback("<%= $this->mycallback->UniqueID %>",
+ * $this->mycallback->ActiveControl->JsCallbackOptions);
+ * </code>
+ * @return string javascript client-side callback request object (javascript
+ * code)
+ */
+ public function getJavascript()
+ {
+ $client = $this->getPage()->getClientScript();
+ return $client->getCallbackReference($this->getControl(),$this->getClientSideOptions());
+ }
+
+ /**
+ * @param string callback requestion options as javascript code.
+ */
+ public function getJsCallbackOptions()
+ {
+ return TJavaScript::encode($this->getClientSideOptions());
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallback.php b/framework/Web/UI/ActiveControls/TCallback.php
index 7a1f54b7..662bc03f 100644
--- a/framework/Web/UI/ActiveControls/TCallback.php
+++ b/framework/Web/UI/ActiveControls/TCallback.php
@@ -1,101 +1,101 @@
-<?php
-/**
- * TCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * Load active control adapter.
- */
-Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
-
-/**
- * TCallback component class.
- *
- * The TCallback provides a basic callback handler that can be invoked from the
- * client side by running the javascript code obtained from the
- * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
- * The event {@link onCallback OnCallback} is raised when a callback is requested made.
- *
- * Example usage:
- * <code>
- * <com:TCallback ID="callback1" OnCallback="callback1_Requested" />
- * <script type="text/javascript">
- * function do_callback1()
- * {
- * var request = <%= $this->callback1->ActiveControl->Javascript %>;
- * request.dispatch();
- * }
- * </script>
- * <div onclick="do_callback1()">Click Me!</div>
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
-{
- /**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, call this constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
- }
-
- /**
- * @return TBaseActiveCallbackControl standard callback options.
- */
- public function getActiveControl()
- {
- return $this->getAdapter()->getBaseActiveControl();
- }
-
- /**
- * @return TCallbackClientSide client side request options.
- */
- public function getClientSide()
- {
- return $this->getAdapter()->getBaseActiveControl()->getClientSide();
- }
-
- /**
- * Raises the callback event. This method is required by
- * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
- * {@link getCausesValidation ActiveControl.CausesValidation} is true,
- * it will invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onCallback OnCallback} event. This method is mainly
- * used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
- */
- public function raiseCallbackEvent($param)
- {
- if($this->getActiveControl()->canCauseValidation())
- $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
- $this->onCallback($param);
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $this->raiseEvent('OnCallback', $this, $param);
- }
-}
-
+<?php
+/**
+ * TCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * Load active control adapter.
+ */
+Prado::using('System.Web.UI.ActiveControls.TActiveControlAdapter');
+
+/**
+ * TCallback component class.
+ *
+ * The TCallback provides a basic callback handler that can be invoked from the
+ * client side by running the javascript code obtained from the
+ * {@link TBaseActiveCallbackControl::getJavascript ActiveControl.Javascript} property.
+ * The event {@link onCallback OnCallback} is raised when a callback is requested made.
+ *
+ * Example usage:
+ * <code>
+ * <com:TCallback ID="callback1" OnCallback="callback1_Requested" />
+ * <script type="text/javascript">
+ * function do_callback1()
+ * {
+ * var request = <%= $this->callback1->ActiveControl->Javascript %>;
+ * request.dispatch();
+ * }
+ * </script>
+ * <div onclick="do_callback1()">Click Me!</div>
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallback extends TControl implements ICallbackEventHandler, IActiveControl
+{
+ /**
+ * Creates a new callback control, sets the adapter to
+ * TActiveControlAdapter. If you override this class, be sure to set the
+ * adapter appropriately by, for example, call this constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAdapter(new TActiveControlAdapter($this));
+ }
+
+ /**
+ * @return TBaseActiveCallbackControl standard callback options.
+ */
+ public function getActiveControl()
+ {
+ return $this->getAdapter()->getBaseActiveControl();
+ }
+
+ /**
+ * @return TCallbackClientSide client side request options.
+ */
+ public function getClientSide()
+ {
+ return $this->getAdapter()->getBaseActiveControl()->getClientSide();
+ }
+
+ /**
+ * Raises the callback event. This method is required by
+ * {@link ICallbackEventHandler ICallbackEventHandler} interface. If
+ * {@link getCausesValidation ActiveControl.CausesValidation} is true,
+ * it will invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onCallback OnCallback} event. This method is mainly
+ * used by framework and control developers.
+ * @param TCallbackEventParameter the event parameter
+ */
+ public function raiseCallbackEvent($param)
+ {
+ if($this->getActiveControl()->canCauseValidation())
+ $this->getPage()->validate($this->getActiveControl()->getValidationGroup());
+ $this->onCallback($param);
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientScript.php b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
index 6dcbe3d0..291f22f2 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientScript.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientScript.php
@@ -1,705 +1,705 @@
-<?php
-/**
- * TCallbackClientScript class file
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientScript class.
- *
- * The TCallbackClientScript class provides corresponding methods that can be
- * executed on the client-side (i.e. the browser client that is viewing
- * the page) during a callback response.
- *
- * The avaiable methods includes setting/clicking input elements, changing Css
- * styles, hiding/showing elements, and adding visual effects to elements on the
- * page. The client-side methods can be access through the CallbackClient
- * property available in TPage.
- *
- * For example, to hide "$myTextBox" element during callback response, do
- * <code>
- * $this->getPage()->getCallbackClient()->hide($myTextBox);
- * </code>
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientScript extends TApplicationComponent
-{
- /**
- * @var TList list of client functions to execute.
- */
- private $_actions;
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- $this->_actions = new TList;
- }
-
- /**
- * @return array list of client function to be executed during callback
- * response.
- */
- public function getClientFunctionsToExecute()
- {
- return $this->_actions->toArray();
- }
-
- /**
- * Executes a client-side statement.
- * @param string javascript function name
- * @param array list of arguments for the function
- */
- public function callClientFunction($function, $params=null)
- {
- if(!is_array($params))
- $params = array($params);
-
- if(count($params) > 0)
- {
- if($params[0] instanceof TControl)
- $params[0] = $params[0]->getClientID();
- }
- $this->_actions->add(array($function => $params));
- }
-
- /**
- * Client script to set the value of a particular input element.
- * @param TControl control element to set the new value
- * @param string new value
- */
- public function setValue($input, $text)
- {
- $this->callClientFunction('Prado.Element.setValue', array($input, $text));
- }
-
- /**
- * Client script to select/clear/check a drop down list, check box list,
- * or radio button list.
- * The second parameter determines the selection method. Valid methods are
- * - <b>Value</b>, select or check by value
- * - <b>Values</b>, select or check by a list of values
- * - <b>Index</b>, select or check by index (zero based index)
- * - <b>Indices</b>, select or check by a list of index (zero based index)
- * - <b>Clear</b>, clears or selections or checks in the list
- * - <b>All</b>, select all
- * - <b>Invert</b>, invert the selection.
- * @param TControl list control
- * @param string selection method
- * @param string|int the value or index to select/check.
- * @param string selection control type, either 'check' or 'select'
- */
- public function select($control, $method='Value', $value=null, $type=null)
- {
- $method = TPropertyValue::ensureEnum($method,
- 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
- $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
- $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
- $this->callClientFunction('Prado.Element.select',
- array($control, $type.$method, $value, $total));
- }
-
- private function getSelectionControlType($control)
- {
- if(is_string($control)) return 'check';
- if($control instanceof TCheckBoxList)
- return 'check';
- if($control instanceof TCheckBox)
- return 'check';
- return 'select';
- }
-
- private function getSelectionControlIsListType($control)
- {
- return $control instanceof TListControl;
- }
-
- /**
- * Client script to click on an element. <b>This client-side function is unpredictable.</b>
- *
- * @param TControl control element or element id
- */
- public function click($control)
- {
- $this->callClientFunction('Prado.Element.click', $control);
- }
-
- /**
- * Client script to check or uncheck a checkbox or radio button.
- * @param TControl control element or element id
- * @param boolean check or uncheck the checkbox or radio button.
- */
- public function check($checkbox, $checked=true)
- {
- $this->select($checkbox, "Value", $checked);
- }
-
- /**
- * Raise the client side event (given by $eventName) on a particular element.
- * @param TControl control element or element id
- * @param string Event name, e.g. "click"
- */
- public function raiseClientEvent($control, $eventName)
- {
- $this->callClientFunction('Event.fireEvent',
- array($control, strtolower($eventName)));
- }
-
- /**
- * Sets the attribute of a particular control.
- * @param TControl control element or element id
- * @param string attribute name
- * @param string attribute value
- */
- public function setAttribute($control, $name, $value)
- {
- // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
- if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
- $control=$control->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
- }
-
- /**
- * Sets the options of a select input element.
- * @param TControl control element or element id
- * @param TCollection a list of new options
- */
- public function setListItems($control, $items)
- {
- $options = array();
- if($control instanceof TListControl)
- {
- $promptText = $control->getPromptText();
- $promptValue = $control->getPromptValue();
-
- if($promptValue==='')
- $promptValue = $promptText;
-
- if($promptValue!=='')
- $options[] = array($promptText, $promptValue);
- }
-
- foreach($items as $item)
- {
- if($item->getHasAttributes())
- $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
- else
- $options[] = array($item->getText(),$item->getValue());
- }
- $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
- }
-
- /**
- * Shows an element by changing its CSS display style as empty.
- * @param TControl control element or element id
- */
- public function show($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.show', $element);
- }
-
- /**
- * Hides an element by changing its CSS display style to "none".
- * @param TControl control element or element id
- */
- public function hide($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.hide', $element);
- }
-
- /**
- * Toggles the visibility of the element.
- * @param TControl control element or element id
- * @param string visual effect, such as, 'appear' or 'slide' or 'blind'.
- * @param array additional options.
- */
- public function toggle($element, $effect=null, $options=array())
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.toggle', array($element,$effect,$options));
- }
-
- /**
- * Removes an element from the HTML page.
- * @param TControl control element or element id
- */
- public function remove($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.remove', $element);
- }
-
- public function addPostDataLoader($name)
- {
- $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name);
- }
-
- /**
- * Update the element's innerHTML with new content.
- * @param TControl control element or element id
- * @param TControl new HTML content, if content is of a TControl, the
- * controls render method is called.
- */
- public function update($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Element.update');
- }
-
- /**
- * Add a Css class name to the element.
- * @param TControl control element or element id
- * @param string CssClass name to add.
- */
- public function addCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.addClassName', array($element, $cssClass));
- }
-
- /**
- * Remove a Css class name from the element.
- * @param TControl control element or element id
- * @param string CssClass name to remove.
- */
- public function removeCssClass($element, $cssClass)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.removeClassName', array($element, $cssClass));
- }
-
- /**
- * Sets the CssClass of an element.
- * @param TControl control element or element id
- * @param string new CssClass name for the element.
- */
- /*public function setCssClass($element, $cssClass)
- {
- $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass));
- }*/
-
- /**
- * Scroll the top of the browser viewing area to the location of the
- * element.
- * @param TControl control element or element id
- */
- public function scrollTo($element)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Element.scrollTo', $element);
- }
-
- /**
- * Focus on a particular element.
- * @param TControl control element or element id.
- */
- public function focus($element)
- {
- $this->callClientFunction('Prado.Element.focus', $element);
- }
-
- /**
- * Sets the style of element. The style must be a key-value array where the
- * key is the style property and the value is the style value.
- * @param TControl control element or element id
- * @param array list of key-value pairs as style property and style value.
- */
- public function setStyle($element, $styles)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction('Prado.Element.setStyle', array($element, $styles));
- }
-
- /**
- * Append a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function appendContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.append');
- }
-
- /**
- * Prepend a HTML fragement to the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function prependContent($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.prepend');
- }
-
- /**
- * Insert a HTML fragement after the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentAfter($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.after');
- }
-
- /**
- * Insert a HTML fragement in before the element.
- * @param TControl control element or element id
- * @param string HTML fragement or the control to be rendered
- */
- public function insertContentBefore($element, $content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content, 'Prado.Element.Insert.before');
- }
-
- /**
- * Replace the content of an element with new content. The new content can
- * be a string or a TControl component. If the <tt>content</tt> parameter is
- * a TControl component, its rendered method will be called and its contents
- * will be used for replacement.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- * @param string replacement method, default is to replace the outter
- * html content.
- * @param string provide a custom boundary.
- * @see insertAbout
- * @see insertBelow
- * @see insertBefore
- * @see insertAfter
- */
- protected function replace($element, $content, $method="Element.replace", $boundary=null)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- $content = null;
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- $content = null;
- }
-
- $this->callClientFunction('Prado.Element.replace',
- array($element, $method, $content, $boundary));
- }
-
- /**
- * Replace the content of an element with new content contained in writer.
- * @param TControl control element or HTML element id.
- * @param string HTML fragement or the control to be rendered
- */
- public function replaceContent($element,$content)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->replace($element, $content);
- }
-
- /**
- * Evaluate a block of javascript enclosed in a boundary.
- * @param THtmlWriter writer for the content.
- */
- public function evaluateScript($writer)
- {
- $this->replace(null, $writer, 'Prado.Element.evaluateScript');
- }
-
- /**
- * Appends a block of inline javascript enclosed in a boundary.
- * Similar to to evaluateScript(), but functions declared in the
- * inline block will be available to page elements.
- * @param THtmlWriter writer for the content.
- */
- public function appendScriptBlock($content)
- {
- if($content instanceof TControl)
- {
- $boundary = $this->getRenderedContentBoundary($content);
- }
- else if($content instanceof THtmlWriter)
- {
- $boundary = $this->getResponseContentBoundary($content);
- }
-
- $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
- }
-
- /**
- * Renders the control and return the content boundary from
- * TCallbackResponseWriter. This method should only be used by framework
- * component developers. The render() method is defered to be called in the
- * TActivePageAdapter class.
- * @param TControl control to be rendered on callback response.
- * @return string the boundary for which the rendered content is wrapped.
- */
- private function getRenderedContentBoundary($control)
- {
- $writer = $this->getResponse()->createHtmlWriter();
- $adapter = $control->getPage()->getAdapter();
- $adapter->registerControlToRender($control, $writer);
- return $writer->getWriter()->getBoundary();
- }
-
- /**
- * @param THtmlWriter the writer responsible for rendering html content.
- * @return string content boundary.
- */
- private function getResponseContentBoundary($html)
- {
- if($html instanceof THtmlWriter)
- {
- if($html->getWriter() instanceof TCallbackResponseWriter)
- return $html->getWriter()->getBoundary();
- }
- return null;
- }
-
- /**
- * Add a visual effect the element.
- * @param string visual effect function name.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function visualEffect($type, $element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->callClientFunction($type, array($element, $options));
- }
-
- /**
- * Visual Effect: Gradually make the element appear.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function appear($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Appear', $element, $options);
- }
-
- /**
- * Visual Effect: Blind down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindDown', $element, $options);
- }
-
- /**
- * Visual Effect: Blind up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function blindUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.BlindUp', $element, $options);
-
- }
-
- /**
- * Visual Effect: Drop out.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function dropOut($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.DropOut', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fade($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fade', $element, $options);
- }
-
- /**
- * Visual Effect: Fold.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function fold($element, $options = null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Fold', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually make an element grow to a predetermined size.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function grow($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Grow', $element, $options);
- }
-
- /**
- * Visual Effect: Gradually grow and fade the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function puff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Puff', $element, $options);
- }
-
- /**
- * Visual Effect: Pulsate.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function pulsate($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Pulsate', $element, $options);
- }
-
- /**
- * Visual Effect: Shake the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shake($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shake', $element, $options);
- }
-
- /**
- * Visual Effect: Shrink the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function shrink($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Shrink', $element, $options);
- }
-
- /**
- * Visual Effect: Slide down.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideDown($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideDown', $element, $options);
- }
-
- /**
- * Visual Effect: Side up.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function slideUp($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SlideUp', $element, $options);
- }
-
- /**
- * Visual Effect: Squish the element.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function squish($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.Squish', $element, $options);
- }
-
- /**
- * Visual Effect: Switch Off effect.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function switchOff($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Effect.SwitchOff', $element, $options);
- }
-
- /**
- * Visual Effect: High light the element for about 2 seconds.
- * @param TControl control element or element id
- * @param array visual effect key-value pair options.
- */
- public function highlight($element, $options=null)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $this->visualEffect('Prado.Effect.Highlight', $element, $options);
- }
-
- /**
- * Set the opacity on a html element or control.
- * @param TControl control element or element id
- * @param float opacity value between 1 and 0
- */
- public function setOpacity($element, $value)
- {
- if ($element instanceof ISurroundable)
- $element=$element->getSurroundingTagID();
- $value = TPropertyValue::ensureFloat($value);
- $this->callClientFunction('Element.setOpacity', array($element,$value));
- }
-}
-
+<?php
+/**
+ * TCallbackClientScript class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientScript class.
+ *
+ * The TCallbackClientScript class provides corresponding methods that can be
+ * executed on the client-side (i.e. the browser client that is viewing
+ * the page) during a callback response.
+ *
+ * The avaiable methods includes setting/clicking input elements, changing Css
+ * styles, hiding/showing elements, and adding visual effects to elements on the
+ * page. The client-side methods can be access through the CallbackClient
+ * property available in TPage.
+ *
+ * For example, to hide "$myTextBox" element during callback response, do
+ * <code>
+ * $this->getPage()->getCallbackClient()->hide($myTextBox);
+ * </code>
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientScript extends TApplicationComponent
+{
+ /**
+ * @var TList list of client functions to execute.
+ */
+ private $_actions;
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->_actions = new TList;
+ }
+
+ /**
+ * @return array list of client function to be executed during callback
+ * response.
+ */
+ public function getClientFunctionsToExecute()
+ {
+ return $this->_actions->toArray();
+ }
+
+ /**
+ * Executes a client-side statement.
+ * @param string javascript function name
+ * @param array list of arguments for the function
+ */
+ public function callClientFunction($function, $params=null)
+ {
+ if(!is_array($params))
+ $params = array($params);
+
+ if(count($params) > 0)
+ {
+ if($params[0] instanceof TControl)
+ $params[0] = $params[0]->getClientID();
+ }
+ $this->_actions->add(array($function => $params));
+ }
+
+ /**
+ * Client script to set the value of a particular input element.
+ * @param TControl control element to set the new value
+ * @param string new value
+ */
+ public function setValue($input, $text)
+ {
+ $this->callClientFunction('Prado.Element.setValue', array($input, $text));
+ }
+
+ /**
+ * Client script to select/clear/check a drop down list, check box list,
+ * or radio button list.
+ * The second parameter determines the selection method. Valid methods are
+ * - <b>Value</b>, select or check by value
+ * - <b>Values</b>, select or check by a list of values
+ * - <b>Index</b>, select or check by index (zero based index)
+ * - <b>Indices</b>, select or check by a list of index (zero based index)
+ * - <b>Clear</b>, clears or selections or checks in the list
+ * - <b>All</b>, select all
+ * - <b>Invert</b>, invert the selection.
+ * @param TControl list control
+ * @param string selection method
+ * @param string|int the value or index to select/check.
+ * @param string selection control type, either 'check' or 'select'
+ */
+ public function select($control, $method='Value', $value=null, $type=null)
+ {
+ $method = TPropertyValue::ensureEnum($method,
+ 'Value', 'Index', 'Clear', 'Indices', 'Values', 'All', 'Invert');
+ $type = ($type===null) ? $this->getSelectionControlType($control) : $type;
+ $total = $this->getSelectionControlIsListType($control) ? $control->getItemCount() : 1;
+ $this->callClientFunction('Prado.Element.select',
+ array($control, $type.$method, $value, $total));
+ }
+
+ private function getSelectionControlType($control)
+ {
+ if(is_string($control)) return 'check';
+ if($control instanceof TCheckBoxList)
+ return 'check';
+ if($control instanceof TCheckBox)
+ return 'check';
+ return 'select';
+ }
+
+ private function getSelectionControlIsListType($control)
+ {
+ return $control instanceof TListControl;
+ }
+
+ /**
+ * Client script to click on an element. <b>This client-side function is unpredictable.</b>
+ *
+ * @param TControl control element or element id
+ */
+ public function click($control)
+ {
+ $this->callClientFunction('Prado.Element.click', $control);
+ }
+
+ /**
+ * Client script to check or uncheck a checkbox or radio button.
+ * @param TControl control element or element id
+ * @param boolean check or uncheck the checkbox or radio button.
+ */
+ public function check($checkbox, $checked=true)
+ {
+ $this->select($checkbox, "Value", $checked);
+ }
+
+ /**
+ * Raise the client side event (given by $eventName) on a particular element.
+ * @param TControl control element or element id
+ * @param string Event name, e.g. "click"
+ */
+ public function raiseClientEvent($control, $eventName)
+ {
+ $this->callClientFunction('Event.fireEvent',
+ array($control, strtolower($eventName)));
+ }
+
+ /**
+ * Sets the attribute of a particular control.
+ * @param TControl control element or element id
+ * @param string attribute name
+ * @param string attribute value
+ */
+ public function setAttribute($control, $name, $value)
+ {
+ // Attributes should be applied on Surrounding tag, except for 'disabled' attribute
+ if ($control instanceof ISurroundable && strtolower($name)!=='disabled')
+ $control=$control->getSurroundingTagID();
+ $this->callClientFunction('Prado.Element.setAttribute',array($control, $name, $value));
+ }
+
+ /**
+ * Sets the options of a select input element.
+ * @param TControl control element or element id
+ * @param TCollection a list of new options
+ */
+ public function setListItems($control, $items)
+ {
+ $options = array();
+ if($control instanceof TListControl)
+ {
+ $promptText = $control->getPromptText();
+ $promptValue = $control->getPromptValue();
+
+ if($promptValue==='')
+ $promptValue = $promptText;
+
+ if($promptValue!=='')
+ $options[] = array($promptText, $promptValue);
+ }
+
+ foreach($items as $item)
+ {
+ if($item->getHasAttributes())
+ $options[] = array($item->getText(),$item->getValue(), $item->getAttributes()->itemAt('Group'));
+ else
+ $options[] = array($item->getText(),$item->getValue());
+ }
+ $this->callClientFunction('Prado.Element.setOptions', array($control, $options));
+ }
+
+ /**
+ * Shows an element by changing its CSS display style as empty.
+ * @param TControl control element or element id
+ */
+ public function show($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.show', $element);
+ }
+
+ /**
+ * Hides an element by changing its CSS display style to "none".
+ * @param TControl control element or element id
+ */
+ public function hide($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.hide', $element);
+ }
+
+ /**
+ * Toggles the visibility of the element.
+ * @param TControl control element or element id
+ * @param string visual effect, such as, 'appear' or 'slide' or 'blind'.
+ * @param array additional options.
+ */
+ public function toggle($element, $effect=null, $options=array())
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.toggle', array($element,$effect,$options));
+ }
+
+ /**
+ * Removes an element from the HTML page.
+ * @param TControl control element or element id
+ */
+ public function remove($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.remove', $element);
+ }
+
+ public function addPostDataLoader($name)
+ {
+ $this->callClientFunction('Prado.CallbackRequest.addPostLoaders', $name);
+ }
+
+ /**
+ * Update the element's innerHTML with new content.
+ * @param TControl control element or element id
+ * @param TControl new HTML content, if content is of a TControl, the
+ * controls render method is called.
+ */
+ public function update($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Element.update');
+ }
+
+ /**
+ * Add a Css class name to the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to add.
+ */
+ public function addCssClass($element, $cssClass)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.addClassName', array($element, $cssClass));
+ }
+
+ /**
+ * Remove a Css class name from the element.
+ * @param TControl control element or element id
+ * @param string CssClass name to remove.
+ */
+ public function removeCssClass($element, $cssClass)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.removeClassName', array($element, $cssClass));
+ }
+
+ /**
+ * Sets the CssClass of an element.
+ * @param TControl control element or element id
+ * @param string new CssClass name for the element.
+ */
+ /*public function setCssClass($element, $cssClass)
+ {
+ $this->callClientFunction('Prado.Element.CssClass.set', array($element, $cssClass));
+ }*/
+
+ /**
+ * Scroll the top of the browser viewing area to the location of the
+ * element.
+ * @param TControl control element or element id
+ */
+ public function scrollTo($element)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Element.scrollTo', $element);
+ }
+
+ /**
+ * Focus on a particular element.
+ * @param TControl control element or element id.
+ */
+ public function focus($element)
+ {
+ $this->callClientFunction('Prado.Element.focus', $element);
+ }
+
+ /**
+ * Sets the style of element. The style must be a key-value array where the
+ * key is the style property and the value is the style value.
+ * @param TControl control element or element id
+ * @param array list of key-value pairs as style property and style value.
+ */
+ public function setStyle($element, $styles)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction('Prado.Element.setStyle', array($element, $styles));
+ }
+
+ /**
+ * Append a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function appendContent($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.append');
+ }
+
+ /**
+ * Prepend a HTML fragement to the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function prependContent($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.prepend');
+ }
+
+ /**
+ * Insert a HTML fragement after the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentAfter($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.after');
+ }
+
+ /**
+ * Insert a HTML fragement in before the element.
+ * @param TControl control element or element id
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function insertContentBefore($element, $content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content, 'Prado.Element.Insert.before');
+ }
+
+ /**
+ * Replace the content of an element with new content. The new content can
+ * be a string or a TControl component. If the <tt>content</tt> parameter is
+ * a TControl component, its rendered method will be called and its contents
+ * will be used for replacement.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered
+ * @param string replacement method, default is to replace the outter
+ * html content.
+ * @param string provide a custom boundary.
+ * @see insertAbout
+ * @see insertBelow
+ * @see insertBefore
+ * @see insertAfter
+ */
+ protected function replace($element, $content, $method="Element.replace", $boundary=null)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ $content = null;
+ }
+ else if($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ $content = null;
+ }
+
+ $this->callClientFunction('Prado.Element.replace',
+ array($element, $method, $content, $boundary));
+ }
+
+ /**
+ * Replace the content of an element with new content contained in writer.
+ * @param TControl control element or HTML element id.
+ * @param string HTML fragement or the control to be rendered
+ */
+ public function replaceContent($element,$content)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->replace($element, $content);
+ }
+
+ /**
+ * Evaluate a block of javascript enclosed in a boundary.
+ * @param THtmlWriter writer for the content.
+ */
+ public function evaluateScript($writer)
+ {
+ $this->replace(null, $writer, 'Prado.Element.evaluateScript');
+ }
+
+ /**
+ * Appends a block of inline javascript enclosed in a boundary.
+ * Similar to to evaluateScript(), but functions declared in the
+ * inline block will be available to page elements.
+ * @param THtmlWriter writer for the content.
+ */
+ public function appendScriptBlock($content)
+ {
+ if($content instanceof TControl)
+ {
+ $boundary = $this->getRenderedContentBoundary($content);
+ }
+ else if($content instanceof THtmlWriter)
+ {
+ $boundary = $this->getResponseContentBoundary($content);
+ }
+
+ $this->callClientFunction('Prado.Element.appendScriptBlock', array($boundary));
+ }
+
+ /**
+ * Renders the control and return the content boundary from
+ * TCallbackResponseWriter. This method should only be used by framework
+ * component developers. The render() method is defered to be called in the
+ * TActivePageAdapter class.
+ * @param TControl control to be rendered on callback response.
+ * @return string the boundary for which the rendered content is wrapped.
+ */
+ private function getRenderedContentBoundary($control)
+ {
+ $writer = $this->getResponse()->createHtmlWriter();
+ $adapter = $control->getPage()->getAdapter();
+ $adapter->registerControlToRender($control, $writer);
+ return $writer->getWriter()->getBoundary();
+ }
+
+ /**
+ * @param THtmlWriter the writer responsible for rendering html content.
+ * @return string content boundary.
+ */
+ private function getResponseContentBoundary($html)
+ {
+ if($html instanceof THtmlWriter)
+ {
+ if($html->getWriter() instanceof TCallbackResponseWriter)
+ return $html->getWriter()->getBoundary();
+ }
+ return null;
+ }
+
+ /**
+ * Add a visual effect the element.
+ * @param string visual effect function name.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function visualEffect($type, $element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->callClientFunction($type, array($element, $options));
+ }
+
+ /**
+ * Visual Effect: Gradually make the element appear.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function appear($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Appear', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Blind down.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindDown($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.BlindDown', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Blind up.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function blindUp($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.BlindUp', $element, $options);
+
+ }
+
+ /**
+ * Visual Effect: Drop out.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function dropOut($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.DropOut', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually fade the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fade($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Fade', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Fold.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function fold($element, $options = null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Fold', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually make an element grow to a predetermined size.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function grow($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Grow', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Gradually grow and fade the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function puff($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Puff', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Pulsate.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function pulsate($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Pulsate', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Shake the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shake($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Shake', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Shrink the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function shrink($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Shrink', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Slide down.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideDown($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SlideDown', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Side up.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function slideUp($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SlideUp', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Squish the element.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function squish($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.Squish', $element, $options);
+ }
+
+ /**
+ * Visual Effect: Switch Off effect.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function switchOff($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Effect.SwitchOff', $element, $options);
+ }
+
+ /**
+ * Visual Effect: High light the element for about 2 seconds.
+ * @param TControl control element or element id
+ * @param array visual effect key-value pair options.
+ */
+ public function highlight($element, $options=null)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $this->visualEffect('Prado.Effect.Highlight', $element, $options);
+ }
+
+ /**
+ * Set the opacity on a html element or control.
+ * @param TControl control element or element id
+ * @param float opacity value between 1 and 0
+ */
+ public function setOpacity($element, $value)
+ {
+ if ($element instanceof ISurroundable)
+ $element=$element->getSurroundingTagID();
+ $value = TPropertyValue::ensureFloat($value);
+ $this->callClientFunction('Element.setOpacity', array($element,$value));
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackClientSide.php b/framework/Web/UI/ActiveControls/TCallbackClientSide.php
index 10231a1c..0d602fa5 100644
--- a/framework/Web/UI/ActiveControls/TCallbackClientSide.php
+++ b/framework/Web/UI/ActiveControls/TCallbackClientSide.php
@@ -1,322 +1,322 @@
-<?php
-/**
- * TCallbackClientSide class file
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackClientSide class.
- *
- * The following client side events are executing in order if the callback
- * request and response are send and received successfuly.
- *
- * - <b>onPreDispatch</b> executed before a request is dispatched.
- * - <b>onUninitialized</b> executed when callback request is uninitialized.
- * - <b>onLoading</b>* executed when callback request is initiated
- * - <b>onLoaded</b>* executed when callback request begins.
- * - <b>onInteractive</b> executed when callback request is in progress.
- * - <b>onComplete</b>executed when callback response returns.
- * - <b>onSuccess</b> executed when callback request returns and is successful.
- * - <b>onFailure</b> executed when callback request returns and fails.
- * - <b>onException</b> raised when callback request fails due to request/response errors.
- *
- * * Note that theses 2 events are not fired correctly by Opera. To make
- * them work in this browser, Prado will fire them just after onPreDispatch.
- *
- * In a general way, onUninitialized, onLoading, onLoaded and onInteractive events
- * are not implemented consistently in all browsers.When cross browser compatibility is
- * needed, it is best to avoid use them
- *
- * The OnSuccess and OnFailure events are raised when the
- * response is returned. A successful request/response will raise
- * OnSuccess event otherwise OnFailure will be raised.
- *
- * - <b>PostState</b> true to collect the form inputs and post them during callback, default is true.
- * - <b>RequestTimeOut</b> The request timeout in milliseconds.
- * - <b>HasPriority</b> true to ensure that the callback request will be sent
- * immediately and will abort existing prioritized requests. It does not affect
- * callbacks that are not prioritized.
- * - <b>EnablePageStateUpdate</b> enable the callback response to enable the
- * viewstate update. This will automatically set HasPriority to true when enabled.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackClientSide extends TClientSideOptions
-{
- /**
- * Returns javascript statement enclosed within a javascript function.
- * @param string javascript statement
- * @return string javascript statement wrapped in a javascript function
- */
- protected function ensureFunction($javascript)
- {
- return "function(sender, parameter){ {$javascript} }";
- }
-
- /**
- * @param string javascript code to be executed before a request is dispatched.
- */
- public function setOnPreDispatch($javascript)
- {
- $this->setFunction('onPreDispatch', $javascript);
- }
-
- /**
- * @return string javascript code to be executed before a request is dispatched.
- */
- public function getOnPreDispatch()
- {
- return $this->getOption('onPreDispatch');
- }
-
- /**
- * @return string javascript code for client-side onUninitialized event
- */
- public function getOnUninitialized()
- {
- return $this->getOption('onUninitialized');
- }
-
- /**
- * @param string javascript code for client-side onUninitialized event.
- */
- public function setOnUninitialized($javascript)
- {
- $this->setFunction('onUninitialized', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoading event
- */
- public function getOnLoading()
- {
- return $this->getOption('onLoading');
- }
-
- /**
- * @param string javascript code for client-side onLoading event.
- */
- public function setOnLoading($javascript)
- {
- $this->setFunction('onLoading', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onLoaded event
- */
- public function getOnLoaded()
- {
- return $this->getOption('onLoaded');
- }
-
- /**
- * @param string javascript code for client-side onLoaded event.
- */
- public function setOnLoaded($javascript)
- {
- $this->setFunction('onLoaded', $javascript);
- }
- /**
- * @return string javascript code for client-side onInteractive event
- */
- public function getOnInteractive()
- {
- return $this->getOption('onInteractive');
- }
-
- /**
- * @param string javascript code for client-side onInteractive event.
- */
- public function setOnInteractive($javascript)
- {
- $this->setFunction('onInteractive', $javascript);
- }
- /**
- * @return string javascript code for client-side onComplete event
- */
- public function getOnComplete()
- {
- return $this->getOption('onComplete');
- }
-
- /**
- * @param string javascript code for client-side onComplete event.
- */
- public function setOnComplete($javascript)
- {
- $this->setFunction('onComplete', $javascript);
- }
- /**
- * @return string javascript code for client-side onSuccess event
- */
- public function getOnSuccess()
- {
- return $this->getOption('onSuccess');
- }
-
- /**
- * @param string javascript code for client-side onSuccess event.
- */
- public function setOnSuccess($javascript)
- {
- $this->setFunction('onSuccess', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onFailure event
- */
- public function getOnFailure()
- {
- return $this->getOption('onFailure');
- }
-
- /**
- * @param string javascript code for client-side onFailure event.
- */
- public function setOnFailure($javascript)
- {
- $this->setFunction('onFailure', $javascript);
- }
-
- /**
- * @return string javascript code for client-side onException event
- */
- public function getOnException()
- {
- return $this->getOption('onException');
- }
-
- /**
- * @param string javascript code for client-side onException event.
- */
- public function setOnException($javascript)
- {
- $this->setFunction('onException', $javascript);
- }
-
- /**
- * @return boolean true to post the inputs of the form on callback, default
- * is post the inputs on callback.
- */
- public function getPostState()
- {
- return $this->getOption('PostInputs');
- }
-
- /**
- * @param boolean true to post the inputs of the form with callback
- * requests. Default is to post the inputs.
- */
- public function setPostState($value)
- {
- $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * @return integer callback request timeout.
- */
- public function getRequestTimeOut()
- {
- return $this->getOption('RequestTimeOut');
- }
-
- /**
- * @param integer callback request timeout
- */
- public function setRequestTimeOut($value)
- {
- $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
- }
-
- /**
- * @return boolean true if the callback request has priority and will abort
- * existing prioritized request in order to send immediately. It does not
- * affect callbacks that are not prioritized. Default is true.
- */
- public function getHasPriority()
- {
- $option = $this->getOption('HasPriority');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @param boolean true to ensure that the callback request will be sent
- * immediately and will abort existing prioritized requests. It does not
- * affect callbacks that are not prioritized.
- */
- public function setHasPriority($value)
- {
- $hasPriority = TPropertyValue::ensureBoolean($value);
- $this->setOption('HasPriority', $hasPriority);
- if(!$hasPriority)
- $this->setEnablePageStateUpdate(false);
- }
-
- /**
- * Set to true to enable the callback response to enable the viewstate
- * update. This will automatically set HasPrority to true.
- * @param boolean true enables the callback response to update the
- * viewstate.
- */
- public function setEnablePageStateUpdate($value)
- {
- $enabled = TPropertyValue::ensureBoolean($value);
- $this->setOption('EnablePageStateUpdate', $enabled);
- if($enabled)
- $this->setHasPriority(true);
- }
-
- /**
- * @return boolean client-side viewstate will be updated on callback
- * response if true. Default is true.
- */
- public function getEnablePageStateUpdate()
- {
- $option = $this->getOption('EnablePageStateUpdate');
- return ($option===null) ? true : $option;
- }
-
- /**
- * @return string post back target ID
- */
- public function getPostBackTarget()
- {
- return $this->getOption('EventTarget');
- }
-
- /**
- * @param string post back target ID
- */
- public function setPostBackTarget($value)
- {
- if($value instanceof TControl)
- $value = $value->getUniqueID();
- $this->setOption('EventTarget', $value);
- }
-
- /**
- * @return string post back event parameter.
- */
- public function getPostBackParameter()
- {
- return $this->getOption('EventParameter');
- }
-
- /**
- * @param string post back event parameter.
- */
- public function setPostBackParameter($value)
- {
- $this->setOption('EventParameter', $value);
- }
-}
-
+<?php
+/**
+ * TCallbackClientSide class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackClientSide class.
+ *
+ * The following client side events are executing in order if the callback
+ * request and response are send and received successfuly.
+ *
+ * - <b>onPreDispatch</b> executed before a request is dispatched.
+ * - <b>onUninitialized</b> executed when callback request is uninitialized.
+ * - <b>onLoading</b>* executed when callback request is initiated
+ * - <b>onLoaded</b>* executed when callback request begins.
+ * - <b>onInteractive</b> executed when callback request is in progress.
+ * - <b>onComplete</b>executed when callback response returns.
+ * - <b>onSuccess</b> executed when callback request returns and is successful.
+ * - <b>onFailure</b> executed when callback request returns and fails.
+ * - <b>onException</b> raised when callback request fails due to request/response errors.
+ *
+ * * Note that theses 2 events are not fired correctly by Opera. To make
+ * them work in this browser, Prado will fire them just after onPreDispatch.
+ *
+ * In a general way, onUninitialized, onLoading, onLoaded and onInteractive events
+ * are not implemented consistently in all browsers.When cross browser compatibility is
+ * needed, it is best to avoid use them
+ *
+ * The OnSuccess and OnFailure events are raised when the
+ * response is returned. A successful request/response will raise
+ * OnSuccess event otherwise OnFailure will be raised.
+ *
+ * - <b>PostState</b> true to collect the form inputs and post them during callback, default is true.
+ * - <b>RequestTimeOut</b> The request timeout in milliseconds.
+ * - <b>HasPriority</b> true to ensure that the callback request will be sent
+ * immediately and will abort existing prioritized requests. It does not affect
+ * callbacks that are not prioritized.
+ * - <b>EnablePageStateUpdate</b> enable the callback response to enable the
+ * viewstate update. This will automatically set HasPriority to true when enabled.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackClientSide extends TClientSideOptions
+{
+ /**
+ * Returns javascript statement enclosed within a javascript function.
+ * @param string javascript statement
+ * @return string javascript statement wrapped in a javascript function
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(sender, parameter){ {$javascript} }";
+ }
+
+ /**
+ * @param string javascript code to be executed before a request is dispatched.
+ */
+ public function setOnPreDispatch($javascript)
+ {
+ $this->setFunction('onPreDispatch', $javascript);
+ }
+
+ /**
+ * @return string javascript code to be executed before a request is dispatched.
+ */
+ public function getOnPreDispatch()
+ {
+ return $this->getOption('onPreDispatch');
+ }
+
+ /**
+ * @return string javascript code for client-side onUninitialized event
+ */
+ public function getOnUninitialized()
+ {
+ return $this->getOption('onUninitialized');
+ }
+
+ /**
+ * @param string javascript code for client-side onUninitialized event.
+ */
+ public function setOnUninitialized($javascript)
+ {
+ $this->setFunction('onUninitialized', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoading event
+ */
+ public function getOnLoading()
+ {
+ return $this->getOption('onLoading');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoading event.
+ */
+ public function setOnLoading($javascript)
+ {
+ $this->setFunction('onLoading', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onLoaded event
+ */
+ public function getOnLoaded()
+ {
+ return $this->getOption('onLoaded');
+ }
+
+ /**
+ * @param string javascript code for client-side onLoaded event.
+ */
+ public function setOnLoaded($javascript)
+ {
+ $this->setFunction('onLoaded', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onInteractive event
+ */
+ public function getOnInteractive()
+ {
+ return $this->getOption('onInteractive');
+ }
+
+ /**
+ * @param string javascript code for client-side onInteractive event.
+ */
+ public function setOnInteractive($javascript)
+ {
+ $this->setFunction('onInteractive', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onComplete event
+ */
+ public function getOnComplete()
+ {
+ return $this->getOption('onComplete');
+ }
+
+ /**
+ * @param string javascript code for client-side onComplete event.
+ */
+ public function setOnComplete($javascript)
+ {
+ $this->setFunction('onComplete', $javascript);
+ }
+ /**
+ * @return string javascript code for client-side onSuccess event
+ */
+ public function getOnSuccess()
+ {
+ return $this->getOption('onSuccess');
+ }
+
+ /**
+ * @param string javascript code for client-side onSuccess event.
+ */
+ public function setOnSuccess($javascript)
+ {
+ $this->setFunction('onSuccess', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onFailure event
+ */
+ public function getOnFailure()
+ {
+ return $this->getOption('onFailure');
+ }
+
+ /**
+ * @param string javascript code for client-side onFailure event.
+ */
+ public function setOnFailure($javascript)
+ {
+ $this->setFunction('onFailure', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side onException event
+ */
+ public function getOnException()
+ {
+ return $this->getOption('onException');
+ }
+
+ /**
+ * @param string javascript code for client-side onException event.
+ */
+ public function setOnException($javascript)
+ {
+ $this->setFunction('onException', $javascript);
+ }
+
+ /**
+ * @return boolean true to post the inputs of the form on callback, default
+ * is post the inputs on callback.
+ */
+ public function getPostState()
+ {
+ return $this->getOption('PostInputs');
+ }
+
+ /**
+ * @param boolean true to post the inputs of the form with callback
+ * requests. Default is to post the inputs.
+ */
+ public function setPostState($value)
+ {
+ $this->setOption('PostInputs', TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * @return integer callback request timeout.
+ */
+ public function getRequestTimeOut()
+ {
+ return $this->getOption('RequestTimeOut');
+ }
+
+ /**
+ * @param integer callback request timeout
+ */
+ public function setRequestTimeOut($value)
+ {
+ $this->setOption('RequestTimeOut', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * @return boolean true if the callback request has priority and will abort
+ * existing prioritized request in order to send immediately. It does not
+ * affect callbacks that are not prioritized. Default is true.
+ */
+ public function getHasPriority()
+ {
+ $option = $this->getOption('HasPriority');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @param boolean true to ensure that the callback request will be sent
+ * immediately and will abort existing prioritized requests. It does not
+ * affect callbacks that are not prioritized.
+ */
+ public function setHasPriority($value)
+ {
+ $hasPriority = TPropertyValue::ensureBoolean($value);
+ $this->setOption('HasPriority', $hasPriority);
+ if(!$hasPriority)
+ $this->setEnablePageStateUpdate(false);
+ }
+
+ /**
+ * Set to true to enable the callback response to enable the viewstate
+ * update. This will automatically set HasPrority to true.
+ * @param boolean true enables the callback response to update the
+ * viewstate.
+ */
+ public function setEnablePageStateUpdate($value)
+ {
+ $enabled = TPropertyValue::ensureBoolean($value);
+ $this->setOption('EnablePageStateUpdate', $enabled);
+ if($enabled)
+ $this->setHasPriority(true);
+ }
+
+ /**
+ * @return boolean client-side viewstate will be updated on callback
+ * response if true. Default is true.
+ */
+ public function getEnablePageStateUpdate()
+ {
+ $option = $this->getOption('EnablePageStateUpdate');
+ return ($option===null) ? true : $option;
+ }
+
+ /**
+ * @return string post back target ID
+ */
+ public function getPostBackTarget()
+ {
+ return $this->getOption('EventTarget');
+ }
+
+ /**
+ * @param string post back target ID
+ */
+ public function setPostBackTarget($value)
+ {
+ if($value instanceof TControl)
+ $value = $value->getUniqueID();
+ $this->setOption('EventTarget', $value);
+ }
+
+ /**
+ * @return string post back event parameter.
+ */
+ public function getPostBackParameter()
+ {
+ return $this->getOption('EventParameter');
+ }
+
+ /**
+ * @param string post back event parameter.
+ */
+ public function setPostBackParameter($value)
+ {
+ $this->setOption('EventParameter', $value);
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
index d4038fb5..7c532588 100644
--- a/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
+++ b/framework/Web/UI/ActiveControls/TCallbackEventParameter.php
@@ -1,87 +1,87 @@
-<?php
-/**
- * TCallbackEventParameter class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackEventParameter class.
- *
- * The TCallbackEventParameter provides the parameter passed during the callback
- * request in the {@link getCallbackParameter CallbackParameter} property. The
- * callback response content (e.g. new HTML content) must be rendered
- * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
- * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
- *
- * Each instance TCallbackResponseWriter is associated with a unique
- * boundary delimited. By default each panel only renders its own content.
- * To replace the content of ONE panel with that of rendered from multiple panels
- * use the same writer instance for the panels to be rendered.
- *
- * The response data (i.e., passing results back to the client-side
- * callback handler function) can be set using {@link setResponseData ResponseData} property.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackEventParameter extends TEventParameter
-{
- /**
- * @var THttpResponse output content.
- */
- private $_response;
- /**
- * @var mixed callback request parameter.
- */
- private $_parameter;
-
- /**
- * Creates a new TCallbackEventParameter.
- */
- public function __construct($response, $parameter)
- {
- $this->_response = $response;
- $this->_parameter = $parameter;
- }
-
- /**
- * @return TCallbackResponseWriter holds the response content.
- */
- public function getNewWriter()
- {
- return $this->_response->createHtmlWriter(null);
- }
-
- /**
- * @return mixed callback request parameter.
- */
- public function getCallbackParameter()
- {
- return $this->_parameter;
- }
-
- /**
- * @param mixed callback response data.
- */
- public function setResponseData($value)
- {
- $this->_response->getAdapter()->setResponseData($value);
- }
-
- /**
- * @return mixed callback response data.
- */
- public function getResponseData()
- {
- return $this->_response->getAdapter()->getResponseData();
- }
-}
-
+<?php
+/**
+ * TCallbackEventParameter class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackEventParameter class.
+ *
+ * The TCallbackEventParameter provides the parameter passed during the callback
+ * request in the {@link getCallbackParameter CallbackParameter} property. The
+ * callback response content (e.g. new HTML content) must be rendered
+ * using an THtmlWriter obtained from the {@link getNewWriter NewWriter}
+ * property, which returns a <b>NEW</b> instance of TCallbackResponseWriter.
+ *
+ * Each instance TCallbackResponseWriter is associated with a unique
+ * boundary delimited. By default each panel only renders its own content.
+ * To replace the content of ONE panel with that of rendered from multiple panels
+ * use the same writer instance for the panels to be rendered.
+ *
+ * The response data (i.e., passing results back to the client-side
+ * callback handler function) can be set using {@link setResponseData ResponseData} property.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @version $Id: TActivePageAdapter.php 1648 2007-01-24 05:52:22Z wei $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackEventParameter extends TEventParameter
+{
+ /**
+ * @var THttpResponse output content.
+ */
+ private $_response;
+ /**
+ * @var mixed callback request parameter.
+ */
+ private $_parameter;
+
+ /**
+ * Creates a new TCallbackEventParameter.
+ */
+ public function __construct($response, $parameter)
+ {
+ $this->_response = $response;
+ $this->_parameter = $parameter;
+ }
+
+ /**
+ * @return TCallbackResponseWriter holds the response content.
+ */
+ public function getNewWriter()
+ {
+ return $this->_response->createHtmlWriter(null);
+ }
+
+ /**
+ * @return mixed callback request parameter.
+ */
+ public function getCallbackParameter()
+ {
+ return $this->_parameter;
+ }
+
+ /**
+ * @param mixed callback response data.
+ */
+ public function setResponseData($value)
+ {
+ $this->_response->getAdapter()->setResponseData($value);
+ }
+
+ /**
+ * @return mixed callback response data.
+ */
+ public function getResponseData()
+ {
+ return $this->_response->getAdapter()->getResponseData();
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TCallbackOptions.php b/framework/Web/UI/ActiveControls/TCallbackOptions.php
index baba32e1..e75c2fde 100644
--- a/framework/Web/UI/ActiveControls/TCallbackOptions.php
+++ b/framework/Web/UI/ActiveControls/TCallbackOptions.php
@@ -1,53 +1,53 @@
-<?php
-/**
- * TCallbackOptions component class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-/**
- * TCallbackOptions class.
- *
- * TCallbackOptions allows common set of callback client-side options
- * to be attached to other active controls.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TCallbackOptions extends TControl
-{
- /**
- * @var TCallbackClientSide client side callback options.
- */
- private $_clientSide;
-
- /**
- * Callback client-side options can be set by setting the properties of
- * the ClientSide property. E.g. <com:TCallbackOptions ClientSide.OnSuccess="..." />
- * See {@link TCallbackClientSide} for details on the properties of
- * ClientSide.
- * @return TCallbackClientSide client-side callback options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientSide();
- return $this->_clientSide;
- }
-
- /**
- * @return TCallbackClientSide callback client-side options.
- */
- protected function createClientSide()
- {
- return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide');
- }
-}
-
+<?php
+/**
+ * TCallbackOptions component class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TCallbackOptions class.
+ *
+ * TCallbackOptions allows common set of callback client-side options
+ * to be attached to other active controls.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TCallbackOptions extends TControl
+{
+ /**
+ * @var TCallbackClientSide client side callback options.
+ */
+ private $_clientSide;
+
+ /**
+ * Callback client-side options can be set by setting the properties of
+ * the ClientSide property. E.g. <com:TCallbackOptions ClientSide.OnSuccess="..." />
+ * See {@link TCallbackClientSide} for details on the properties of
+ * ClientSide.
+ * @return TCallbackClientSide client-side callback options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TCallbackClientSide callback client-side options.
+ */
+ protected function createClientSide()
+ {
+ return Prado::createComponent('System.Web.UI.ActiveControls.TCallbackClientSide');
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
index c28b435c..38aaabec 100644
--- a/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TEventTriggeredCallback.php
@@ -1,95 +1,95 @@
-<?php
-/**
- * TEventTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TEventTriggeredCallback Class
- *
- * Triggers a new callback request when a particular {@link setEventName EventName}
- * on a control with ID given by {@link setControlID ControlID} is raised.
- *
- * The default action of the event on the client-side can be prevented when
- * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TEventTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The client-side event name the trigger listens to.
- */
- public function getEventName()
- {
- return $this->getViewState('EventName', '');
- }
-
- /**
- * Sets the client-side event name that fires the callback request.
- * @param string The client-side event name the trigger listens to.
- */
- public function setEventName($value)
- {
- $this->setViewState('EventName', $value, '');
- }
-
- /**
- * @param boolean true to prevent/stop default event action.
- */
- public function setPreventDefaultAction($value)
- {
- $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
- }
-
- /**
- * @return boolean true to prevent/stop default event action.
- */
- public function getPreventDefaultAction()
- {
- return $this->getViewState('StopEvent', false);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $name = preg_replace('/^on/', '', $this->getEventName());
- $options['EventName'] = strtolower($name);
- $options['StopEvent'] = $this->getPreventDefaultAction();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEventTriggeredCallback';
- }
-}
-
+<?php
+/**
+ * TEventTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TEventTriggeredCallback Class
+ *
+ * Triggers a new callback request when a particular {@link setEventName EventName}
+ * on a control with ID given by {@link setControlID ControlID} is raised.
+ *
+ * The default action of the event on the client-side can be prevented when
+ * {@link setPreventDefaultAction PreventDefaultAction} is set to true.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TEventTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The client-side event name the trigger listens to.
+ */
+ public function getEventName()
+ {
+ return $this->getViewState('EventName', '');
+ }
+
+ /**
+ * Sets the client-side event name that fires the callback request.
+ * @param string The client-side event name the trigger listens to.
+ */
+ public function setEventName($value)
+ {
+ $this->setViewState('EventName', $value, '');
+ }
+
+ /**
+ * @param boolean true to prevent/stop default event action.
+ */
+ public function setPreventDefaultAction($value)
+ {
+ $this->setViewState('StopEvent', TPropertyValue::ensureBoolean($value), false);
+ }
+
+ /**
+ * @return boolean true to prevent/stop default event action.
+ */
+ public function getPreventDefaultAction()
+ {
+ return $this->getViewState('StopEvent', false);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $name = preg_replace('/^on/', '', $this->getEventName());
+ $options['EventName'] = strtolower($name);
+ $options['StopEvent'] = $this->getPreventDefaultAction();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEventTriggeredCallback';
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
index aba477b9..47c8aeac 100644
--- a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
+++ b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
@@ -1,290 +1,290 @@
-<?php
-/**
- * TInPlaceTextBox class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
-
-/**
- * TInPlaceTextBox Class
- * *
- * TInPlaceTextBox is a component rendered as a label and allows its
- * contents to be edited by changing the label to a textbox when
- * the label is clicked or when another control or html element with
- * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
- *
- * If the {@link OnLoadingText} event is handled, a callback request is
- * made when the label is clicked, while the request is being made the
- * textbox is disabled from editing. The {@link OnLoadingText} event allows
- * you to update the content of the textbox before the client is allowed
- * to edit the content. After the callback request returns successfully,
- * the textbox is enabled and the contents is then allowed to be edited.
- *
- * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
- * is true and the textbox content has changed, a callback request is made and
- * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
- * During the request, the textbox is disabled.
- *
- * After the callback request returns sucessfully, the textbox is enabled.
- * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
- * the textbox will be hidden and the label is then shown.
- *
- * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
- * the control not editable. This property can be also changed on callback
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TInPlaceTextBox extends TActiveTextBox
-{
- /**
- * Sets the auto post back to true by default.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setAutoPostBack(true);
- }
-
- /**
- * @param boolean true to hide the textbox after losing focus.
- */
- public function setAutoHideTextBox($value)
- {
- $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return boolean true will hide the textbox after losing focus.
- */
- public function getAutoHideTextBox()
- {
- return $this->getViewState('AutoHide', true);
- }
-
- /**
- * @param boolean true to display the edit textbox
- */
- public function setDisplayTextBox($value)
- {
- $value = TPropertyValue::ensureBoolean($value);
- $this->setViewState('DisplayTextBox', $value,false);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->callClientFunction('setDisplayTextBox',$value);
- }
-
- /**
- * @return boolean true to display the edit textbox
- */
- public function getDisplayTextBox()
- {
- return $this->getViewState('DisplayTextBox', false);
- }
-
- /**
- * Calls the client-side static method for this control class.
- * @param string static method name
- * @param mixed method parmaeter
- */
- protected function callClientFunction($func,$value)
- {
- $client = $this->getPage()->getCallbackClient();
- $code = $this->getClientClassName().'.'.$func;
- $client->callClientFunction($code,array($this,$value));
- }
-
- /**
- * @param string ID of the control that can trigger to edit the textbox
- */
- public function setEditTriggerControlID($value)
- {
- $this->setViewState('EditTriggerControlID', $value);
- }
-
- /**
- * @return string ID of the control that can trigger to edit the textbox
- */
- public function getEditTriggerControlID()
- {
- return $this->getViewState('EditTriggerControlID');
- }
-
- /**
- * @return string edit trigger control client ID.
- */
- protected function getExternalControlID()
- {
- $extID = $this->getEditTriggerControlID();
- if($extID===null) return '';
- if(($control = $this->findControl($extID))!==null)
- return $control->getClientID();
- return $extID;
- }
-
- /**
- * On callback response, the inner HTMl of the label and the
- * value of the textbox is updated
- * @param string the text value of the label
- */
- public function setText($value)
- {
- TTextBox::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- {
- $client = $this->getPage()->getCallbackClient();
- $client->update($this->getLabelClientID(), $value);
- $client->setValue($this, $value);
- }
- }
-
- /**
- * Update ClientSide Readonly property
- * @param boolean value
- * @since 3.1.2
- */
- public function setReadOnly ($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- TTextBox::setReadOnly($value);
- if ($this->getActiveControl()->canUpdateClientSide())
- {
- $this->callClientFunction('setReadOnly', $value);
- }
- }
-
- /**
- * @return string tag name of the label.
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Renders the body content of the label.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string label client ID
- */
- protected function getLabelClientID()
- {
- return $this->getClientID().'__label';
- }
-
- /**
- * This method is invoked when a callback is requested. The method raises
- * 'OnCallback' event to fire up the event handlers. If you override this
- * method, be sure to call the parent implementation so that the event
- * handler can be invoked.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onCallback($param)
- {
- $action = $param->getCallbackParameter();
- if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
- {
- $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
- $this->onLoadingText($parameter);
- }
- $this->raiseEvent('OnCallback', $this, $param);
- }
-
- /**
- * @return array callback options.
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['ID'] = $this->getLabelClientID();
- $options['TextBoxID'] = $this->getClientID();
- $options['ExternalControl'] = $this->getExternalControlID();
- $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
- $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
- $options['Columns'] = $this->getColumns();
- if($this->getTextMode()==='MultiLine')
- {
- $options['Rows'] = $this->getRows();
- $options['Wrap'] = $this->getWrap()== false ? '' : true;
- }
- else
- {
- $length = $this->getMaxLength();
- $options['MaxLength'] = $length > 0 ? $length : '';
- }
-
- if($this->hasEventHandler('OnLoadingText'))
- $options['LoadTextOnEdit'] = true;
-
- $options['ReadOnly']=$this->getReadOnly();
- return $options;
- }
-
- /**
- * Raised when editing the content is requsted to be loaded from the
- * server side.
- * @param TCallbackEventParameter event parameter to be passed to the event handlers
- */
- public function onLoadingText($param)
- {
- $this->raiseEvent('OnLoadingText',$this,$param);
- }
-
- /**
- * @return string corresponding javascript class name for this TInPlaceTextBox
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TInPlaceTextBox';
- }
-
- /**
- * Ensure that the ID attribute is rendered and registers the javascript code
- * for initializing the active control.
- */
- protected function addAttributesToRender($writer)
- {
- //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
- TWebControl::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getLabelClientID());
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getPostBackOptions());
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->registerClientScript();
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('inlineeditor');
- }
-}
+<?php
+/**
+ * TInPlaceTextBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TActiveTextBox');
+
+/**
+ * TInPlaceTextBox Class
+ * *
+ * TInPlaceTextBox is a component rendered as a label and allows its
+ * contents to be edited by changing the label to a textbox when
+ * the label is clicked or when another control or html element with
+ * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
+ *
+ * If the {@link OnLoadingText} event is handled, a callback request is
+ * made when the label is clicked, while the request is being made the
+ * textbox is disabled from editing. The {@link OnLoadingText} event allows
+ * you to update the content of the textbox before the client is allowed
+ * to edit the content. After the callback request returns successfully,
+ * the textbox is enabled and the contents is then allowed to be edited.
+ *
+ * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
+ * is true and the textbox content has changed, a callback request is made and
+ * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
+ * During the request, the textbox is disabled.
+ *
+ * After the callback request returns sucessfully, the textbox is enabled.
+ * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
+ * the textbox will be hidden and the label is then shown.
+ *
+ * Since 3.1.2, you can set the {@link setReadOnly ReadOnly} property to make
+ * the control not editable. This property can be also changed on callback
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInPlaceTextBox extends TActiveTextBox
+{
+ /**
+ * Sets the auto post back to true by default.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @param boolean true to hide the textbox after losing focus.
+ */
+ public function setAutoHideTextBox($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return boolean true will hide the textbox after losing focus.
+ */
+ public function getAutoHideTextBox()
+ {
+ return $this->getViewState('AutoHide', true);
+ }
+
+ /**
+ * @param boolean true to display the edit textbox
+ */
+ public function setDisplayTextBox($value)
+ {
+ $value = TPropertyValue::ensureBoolean($value);
+ $this->setViewState('DisplayTextBox', $value,false);
+ if($this->getActiveControl()->canUpdateClientSide())
+ $this->callClientFunction('setDisplayTextBox',$value);
+ }
+
+ /**
+ * @return boolean true to display the edit textbox
+ */
+ public function getDisplayTextBox()
+ {
+ return $this->getViewState('DisplayTextBox', false);
+ }
+
+ /**
+ * Calls the client-side static method for this control class.
+ * @param string static method name
+ * @param mixed method parmaeter
+ */
+ protected function callClientFunction($func,$value)
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $code = $this->getClientClassName().'.'.$func;
+ $client->callClientFunction($code,array($this,$value));
+ }
+
+ /**
+ * @param string ID of the control that can trigger to edit the textbox
+ */
+ public function setEditTriggerControlID($value)
+ {
+ $this->setViewState('EditTriggerControlID', $value);
+ }
+
+ /**
+ * @return string ID of the control that can trigger to edit the textbox
+ */
+ public function getEditTriggerControlID()
+ {
+ return $this->getViewState('EditTriggerControlID');
+ }
+
+ /**
+ * @return string edit trigger control client ID.
+ */
+ protected function getExternalControlID()
+ {
+ $extID = $this->getEditTriggerControlID();
+ if($extID===null) return '';
+ if(($control = $this->findControl($extID))!==null)
+ return $control->getClientID();
+ return $extID;
+ }
+
+ /**
+ * On callback response, the inner HTMl of the label and the
+ * value of the textbox is updated
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ TTextBox::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->update($this->getLabelClientID(), $value);
+ $client->setValue($this, $value);
+ }
+ }
+
+ /**
+ * Update ClientSide Readonly property
+ * @param boolean value
+ * @since 3.1.2
+ */
+ public function setReadOnly ($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ TTextBox::setReadOnly($value);
+ if ($this->getActiveControl()->canUpdateClientSide())
+ {
+ $this->callClientFunction('setReadOnly', $value);
+ }
+ }
+
+ /**
+ * @return string tag name of the label.
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string label client ID
+ */
+ protected function getLabelClientID()
+ {
+ return $this->getClientID().'__label';
+ }
+
+ /**
+ * This method is invoked when a callback is requested. The method raises
+ * 'OnCallback' event to fire up the event handlers. If you override this
+ * method, be sure to call the parent implementation so that the event
+ * handler can be invoked.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCallback($param)
+ {
+ $action = $param->getCallbackParameter();
+ if(is_array($action) && $action[0] === '__InlineEditor_loadExternalText__')
+ {
+ $parameter = new TCallbackEventParameter($this->getResponse(), $action[1]);
+ $this->onLoadingText($parameter);
+ }
+ $this->raiseEvent('OnCallback', $this, $param);
+ }
+
+ /**
+ * @return array callback options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['ID'] = $this->getLabelClientID();
+ $options['TextBoxID'] = $this->getClientID();
+ $options['ExternalControl'] = $this->getExternalControlID();
+ $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
+ $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
+ $options['Columns'] = $this->getColumns();
+ if($this->getTextMode()==='MultiLine')
+ {
+ $options['Rows'] = $this->getRows();
+ $options['Wrap'] = $this->getWrap()== false ? '' : true;
+ }
+ else
+ {
+ $length = $this->getMaxLength();
+ $options['MaxLength'] = $length > 0 ? $length : '';
+ }
+
+ if($this->hasEventHandler('OnLoadingText'))
+ $options['LoadTextOnEdit'] = true;
+
+ $options['ReadOnly']=$this->getReadOnly();
+ return $options;
+ }
+
+ /**
+ * Raised when editing the content is requsted to be loaded from the
+ * server side.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoadingText($param)
+ {
+ $this->raiseEvent('OnLoadingText',$this,$param);
+ }
+
+ /**
+ * @return string corresponding javascript class name for this TInPlaceTextBox
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TInPlaceTextBox';
+ }
+
+ /**
+ * Ensure that the ID attribute is rendered and registers the javascript code
+ * for initializing the active control.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ //calls the TWebControl to avoid rendering other attribute normally render for a textbox.
+ TWebControl::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getLabelClientID());
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->registerClientScript();
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('inlineeditor');
+ }
+}
diff --git a/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
index fd1fabb1..4b89cb8e 100644
--- a/framework/Web/UI/ActiveControls/TTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
@@ -1,71 +1,71 @@
-<?php
-/**
- * TTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TCallback');
-/**
- * TTriggeredCallback abstract Class
- *
- * Base class for triggered callback controls. The {@link setControlID ControlID}
- * property sets the control ID to observe the trigger.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-abstract class TTriggeredCallback extends TCallback
-{
- /**
- * @return string The ID of the server control the trigger is bounded to.
- */
- public function getControlID()
- {
- return $this->getViewState('ControlID', '');
- }
-
- /**
- * @param string The ID of the server control the trigger is bounded to.
- */
- public function setControlID($value)
- {
- $this->setViewState('ControlID', $value, '');
- }
-
- /**
- * @return string target control client ID or html element ID if
- * control is not found in hierarchy.
- */
- protected function getTargetControl()
- {
- $id = $this->getControlID();
- if(($control=$this->findControl($id)) instanceof TControl)
- return $control->getClientID();
- if($id==='')
- {
- throw new TConfigurationException(
- 'ttriggeredcallback_invalid_controlid', get_class($this));
- }
- return $id;
- }
-
- /**
- * @return array list of trigger callback options.
- */
- protected function getTriggerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['ControlID'] = $this->getTargetControl();
- return $options;
- }
-}
-
+<?php
+/**
+ * TTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TCallback');
+/**
+ * TTriggeredCallback abstract Class
+ *
+ * Base class for triggered callback controls. The {@link setControlID ControlID}
+ * property sets the control ID to observe the trigger.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+abstract class TTriggeredCallback extends TCallback
+{
+ /**
+ * @return string The ID of the server control the trigger is bounded to.
+ */
+ public function getControlID()
+ {
+ return $this->getViewState('ControlID', '');
+ }
+
+ /**
+ * @param string The ID of the server control the trigger is bounded to.
+ */
+ public function setControlID($value)
+ {
+ $this->setViewState('ControlID', $value, '');
+ }
+
+ /**
+ * @return string target control client ID or html element ID if
+ * control is not found in hierarchy.
+ */
+ protected function getTargetControl()
+ {
+ $id = $this->getControlID();
+ if(($control=$this->findControl($id)) instanceof TControl)
+ return $control->getClientID();
+ if($id==='')
+ {
+ throw new TConfigurationException(
+ 'ttriggeredcallback_invalid_controlid', get_class($this));
+ }
+ return $id;
+ }
+
+ /**
+ * @return array list of trigger callback options.
+ */
+ protected function getTriggerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ControlID'] = $this->getTargetControl();
+ return $options;
+ }
+}
+
diff --git a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
index 58a78d08..899419ee 100644
--- a/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TValueTriggeredCallback.php
@@ -1,120 +1,120 @@
-<?php
-/**
- * TValueTriggeredCallback class file.
- *
- * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- */
-
-Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
-
-/**
- * TValueTriggeredCallback Class
- *
- * Observes the value with {@link setPropertyName PropertyName} of a
- * control with {@link setControlID ControlID}. Changes to the observed
- * property value will trigger a new callback request. The property value is checked
- * for changes every{@link setInterval Interval} seconds.
- *
- * A {@link setDecayRate DecayRate} can be set to increase the polling
- * interval linearly if no changes are observed. Once a change is
- * observed, the polling interval is reset to the original value.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.ActiveControls
- * @since 3.1
- */
-class TValueTriggeredCallback extends TTriggeredCallback
-{
- /**
- * @return string The control property name to observe value changes.
- */
- public function getPropertyName()
- {
- return $this->getViewState('PropertyName', '');
- }
-
- /**
- * Sets the control property name to observe value changes that fires the callback request.
- * @param string The control property name to observe value changes.
- */
- public function setPropertyName($value)
- {
- $this->setViewState('PropertyName', $value, '');
- }
-
- /**
- * Sets the polling interval in seconds to observe property changes.
- * Default is 1 second.
- * @param float polling interval in seconds.
- */
- public function setInterval($value)
- {
- $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
- }
-
- /**
- * @return float polling interval, 1 second default.
- */
- public function getInterval()
- {
- return $this->getViewState('Interval', 1);
- }
-
- /**
- * Gets the decay rate between callbacks. Default is 0;
- * @return float decay rate between callbacks.
- */
- public function getDecayRate()
- {
- return $this->getViewState('Decay', 0);
- }
-
- /**
- * Sets the decay rate between callback. Default is 0;
- * @param float decay rate between callbacks.
- */
- public function setDecayRate($value)
- {
- $decay = TPropertyValue::ensureFloat($value);
- if($decay < 0)
- throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
- $this->setViewState('Decay', $decay);
- }
-
- /**
- * @return array list of timer options for client-side.
- */
- protected function getTriggerOptions()
- {
- $options = parent::getTriggerOptions();
- $options['PropertyName'] = $this->getPropertyName();
- $options['Interval'] = $this->getInterval();
- $options['Decay'] = $this->getDecayRate();
- return $options;
- }
-
- /**
- * Registers the javascript code for initializing the active control.
- * @param THtmlWriter the renderer.
- */
- public function render($writer)
- {
- parent::render($writer);
- $this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTriggerOptions());
- }
-
- /**
- * @return string corresponding javascript class name for TEventTriggeredCallback.
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TValueTriggeredCallback';
- }
-}
+<?php
+/**
+ * TValueTriggeredCallback class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ */
+
+Prado::using('System.Web.UI.ActiveControls.TTriggeredCallback');
+
+/**
+ * TValueTriggeredCallback Class
+ *
+ * Observes the value with {@link setPropertyName PropertyName} of a
+ * control with {@link setControlID ControlID}. Changes to the observed
+ * property value will trigger a new callback request. The property value is checked
+ * for changes every{@link setInterval Interval} seconds.
+ *
+ * A {@link setDecayRate DecayRate} can be set to increase the polling
+ * interval linearly if no changes are observed. Once a change is
+ * observed, the polling interval is reset to the original value.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TValueTriggeredCallback extends TTriggeredCallback
+{
+ /**
+ * @return string The control property name to observe value changes.
+ */
+ public function getPropertyName()
+ {
+ return $this->getViewState('PropertyName', '');
+ }
+
+ /**
+ * Sets the control property name to observe value changes that fires the callback request.
+ * @param string The control property name to observe value changes.
+ */
+ public function setPropertyName($value)
+ {
+ $this->setViewState('PropertyName', $value, '');
+ }
+
+ /**
+ * Sets the polling interval in seconds to observe property changes.
+ * Default is 1 second.
+ * @param float polling interval in seconds.
+ */
+ public function setInterval($value)
+ {
+ $this->setViewState('Interval', TPropertyValue::ensureFloat($value), 1);
+ }
+
+ /**
+ * @return float polling interval, 1 second default.
+ */
+ public function getInterval()
+ {
+ return $this->getViewState('Interval', 1);
+ }
+
+ /**
+ * Gets the decay rate between callbacks. Default is 0;
+ * @return float decay rate between callbacks.
+ */
+ public function getDecayRate()
+ {
+ return $this->getViewState('Decay', 0);
+ }
+
+ /**
+ * Sets the decay rate between callback. Default is 0;
+ * @param float decay rate between callbacks.
+ */
+ public function setDecayRate($value)
+ {
+ $decay = TPropertyValue::ensureFloat($value);
+ if($decay < 0)
+ throw new TConfigurationException('callback_decay_be_not_negative', $this->getID());
+ $this->setViewState('Decay', $decay);
+ }
+
+ /**
+ * @return array list of timer options for client-side.
+ */
+ protected function getTriggerOptions()
+ {
+ $options = parent::getTriggerOptions();
+ $options['PropertyName'] = $this->getPropertyName();
+ $options['Interval'] = $this->getInterval();
+ $options['Decay'] = $this->getDecayRate();
+ return $options;
+ }
+
+ /**
+ * Registers the javascript code for initializing the active control.
+ * @param THtmlWriter the renderer.
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+ $this->getActiveControl()->registerCallbackClientScript(
+ $this->getClientClassName(), $this->getTriggerOptions());
+ }
+
+ /**
+ * @return string corresponding javascript class name for TEventTriggeredCallback.
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TValueTriggeredCallback';
+ }
+}
diff --git a/framework/Web/UI/TCachePageStatePersister.php b/framework/Web/UI/TCachePageStatePersister.php
index 486c87ca..34b9203a 100644
--- a/framework/Web/UI/TCachePageStatePersister.php
+++ b/framework/Web/UI/TCachePageStatePersister.php
@@ -1,200 +1,200 @@
-<?php
-/**
- * TCachePageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCachePageStatePersister class
- *
- * TCachePageStatePersister implements a page state persistent method based on cache.
- * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
- * is passed to the client side to identify the state. This greatly reduces the size of
- * the page state that needs to be transmitted between the server and the client. Of course,
- * this is at the cost of using server side resource.
- *
- * A cache module has to be loaded in order to use TCachePageStatePersister.
- * By default, TCachePageStatePersister will use the primary cache module.
- * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
- * Any cache module, as long as it implements the interface {@link ICache}, may be used.
- * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
- *
- * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
- * that stores in cache.
- *
- * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
- * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
- *
- * There are a couple of ways to use TCachePageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TCachePageStatePersister instance there.
- * Or one can configure the pages to use TCachePageStatePersister in page configurations
- * as follows,
- * <code>
- * <pages StatePersisterClass="System.Web.UI.TCachePageStatePersister"
- * StatePersister.CacheModuleID="mycache"
- * StatePersister.CacheTimeout="3600" />
- * </code>
- * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
- * for the TCachePageStatePersister instance.
- *
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TCachePageStatePersister, use
- * <code>
- * <pages>
- * <page id="PageID" StatePersisterClass="System.Web.UI.TCachePageStatePersister" />
- * </pages>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1.1
- */
-class TCachePageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_prefix='statepersister';
- private $_page;
- private $_cache=null;
- private $_cacheModuleID='';
- private $_timeout=1800;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return string the ID of the cache module.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If not set, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * @return ICache the cache module being used for data storage
- */
- public function getCache()
- {
- if($this->_cache===null)
- {
- if($this->_cacheModuleID!=='')
- $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
- else
- $cache=Prado::getApplication()->getCache();
- if($cache===null || !($cache instanceof ICache))
- {
- if($this->_cacheModuleID!=='')
- throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
- else
- throw new TConfigurationException('cachepagestatepersister_cache_required');
- }
- $this->_cache=$cache;
- }
- return $this->_cache;
- }
-
- /**
- * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
- */
- public function getCacheTimeout()
- {
- return $this->_timeout;
- }
-
- /**
- * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
- * @throws TInvalidDataValueException if the number is smaller than 0.
- */
- public function setCacheTimeout($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>=0)
- $this->_timeout=$value;
- else
- throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
- }
-
- /**
- * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
- */
- public function getKeyPrefix()
- {
- return $this->_prefix;
- }
-
- /**
- * @param string prefix of cache variable name to avoid conflict with other cache data
- */
- public function setKeyPrefix($value)
- {
- $this->_prefix=$value;
- }
-
- /**
- * @param string micro timestamp when saving state occurs
- * @return string a key that is unique per user request
- */
- protected function calculateKey($timestamp)
- {
- return $this->getKeyPrefix().':'
- . $this->_page->getRequest()->getUserHostAddress()
- . $this->_page->getPagePath()
- . $timestamp;
- }
-
- /**
- * Saves state in cache.
- * @param mixed state to be stored
- */
- public function save($data)
- {
- $timestamp=(string)microtime(true);
- $key=$this->calculateKey($timestamp);
- $this->getCache()->add($key,$data,$this->_timeout);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from cache.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $key=$this->calculateKey($timestamp);
- if(($data=$this->getCache()->get($key))!==false)
- return $data;
- }
- throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
- }
-}
-
+<?php
+/**
+ * TCachePageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TCachePageStatePersister class
+ *
+ * TCachePageStatePersister implements a page state persistent method based on cache.
+ * Page state are stored in cache (e.g. memcache, DB cache, etc.), and only a small token
+ * is passed to the client side to identify the state. This greatly reduces the size of
+ * the page state that needs to be transmitted between the server and the client. Of course,
+ * this is at the cost of using server side resource.
+ *
+ * A cache module has to be loaded in order to use TCachePageStatePersister.
+ * By default, TCachePageStatePersister will use the primary cache module.
+ * A non-primary cache module can be used by setting {@link setCacheModuleID CacheModuleID}.
+ * Any cache module, as long as it implements the interface {@link ICache}, may be used.
+ * For example, one can use {@link TDbCache}, {@link TMemCache}, {@link TAPCCache}, etc.
+ *
+ * TCachePageStatePersister uses {@link setCacheTimeout CacheTimeout} to limit the data
+ * that stores in cache.
+ *
+ * Since server resource is often limited, be cautious if you plan to use TCachePageStatePersister
+ * for high-traffic Web pages. You may consider using a small {@link setCacheTimeout CacheTimeout}.
+ *
+ * There are a couple of ways to use TCachePageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TCachePageStatePersister instance there.
+ * Or one can configure the pages to use TCachePageStatePersister in page configurations
+ * as follows,
+ * <code>
+ * <pages StatePersisterClass="System.Web.UI.TCachePageStatePersister"
+ * StatePersister.CacheModuleID="mycache"
+ * StatePersister.CacheTimeout="3600" />
+ * </code>
+ * Note in the above, we use StatePersister.CacheModuleID to configure the cache module ID
+ * for the TCachePageStatePersister instance.
+ *
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TCachePageStatePersister, use
+ * <code>
+ * <pages>
+ * <page id="PageID" StatePersisterClass="System.Web.UI.TCachePageStatePersister" />
+ * </pages>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1.1
+ */
+class TCachePageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_prefix='statepersister';
+ private $_page;
+ private $_cache=null;
+ private $_cacheModuleID='';
+ private $_timeout=1800;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return string the ID of the cache module.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If not set, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * @return ICache the cache module being used for data storage
+ */
+ public function getCache()
+ {
+ if($this->_cache===null)
+ {
+ if($this->_cacheModuleID!=='')
+ $cache=Prado::getApplication()->getModule($this->_cacheModuleID);
+ else
+ $cache=Prado::getApplication()->getCache();
+ if($cache===null || !($cache instanceof ICache))
+ {
+ if($this->_cacheModuleID!=='')
+ throw new TConfigurationException('cachepagestatepersister_cachemoduleid_invalid',$this->_cacheModuleID);
+ else
+ throw new TConfigurationException('cachepagestatepersister_cache_required');
+ }
+ $this->_cache=$cache;
+ }
+ return $this->_cache;
+ }
+
+ /**
+ * @return integer the number of seconds in which the cached state will expire. Defaults to 1800.
+ */
+ public function getCacheTimeout()
+ {
+ return $this->_timeout;
+ }
+
+ /**
+ * @param integer the number of seconds in which the cached state will expire. 0 means never expire.
+ * @throws TInvalidDataValueException if the number is smaller than 0.
+ */
+ public function setCacheTimeout($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>=0)
+ $this->_timeout=$value;
+ else
+ throw new TInvalidDataValueException('cachepagestatepersister_timeout_invalid');
+ }
+
+ /**
+ * @return string prefix of cache variable name to avoid conflict with other cache data. Defaults to 'statepersister'.
+ */
+ public function getKeyPrefix()
+ {
+ return $this->_prefix;
+ }
+
+ /**
+ * @param string prefix of cache variable name to avoid conflict with other cache data
+ */
+ public function setKeyPrefix($value)
+ {
+ $this->_prefix=$value;
+ }
+
+ /**
+ * @param string micro timestamp when saving state occurs
+ * @return string a key that is unique per user request
+ */
+ protected function calculateKey($timestamp)
+ {
+ return $this->getKeyPrefix().':'
+ . $this->_page->getRequest()->getUserHostAddress()
+ . $this->_page->getPagePath()
+ . $timestamp;
+ }
+
+ /**
+ * Saves state in cache.
+ * @param mixed state to be stored
+ */
+ public function save($data)
+ {
+ $timestamp=(string)microtime(true);
+ $key=$this->calculateKey($timestamp);
+ $this->getCache()->add($key,$data,$this->_timeout);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from cache.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $key=$this->calculateKey($timestamp);
+ if(($data=$this->getCache()->get($key))!==false)
+ return $data;
+ }
+ throw new THttpException(400,'cachepagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TCompositeControl.php b/framework/Web/UI/TCompositeControl.php
index 285a8129..e7766ab8 100644
--- a/framework/Web/UI/TCompositeControl.php
+++ b/framework/Web/UI/TCompositeControl.php
@@ -1,38 +1,38 @@
-<?php
-/**
- * TCompositeControl class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TCompositeControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TCompositeControl class.
- * TCompositeControl is the base class for controls that are composed
- * by other controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeControl extends TControl implements INamingContainer
-{
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TCompositeControl class.
+ * TCompositeControl is the base class for controls that are composed
+ * by other controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeControl extends TControl implements INamingContainer
+{
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ parent::initRecursive($namingContainer);
+ }
+}
+
diff --git a/framework/Web/UI/TControl.php b/framework/Web/UI/TControl.php
index 316098a1..2adabb55 100644
--- a/framework/Web/UI/TControl.php
+++ b/framework/Web/UI/TControl.php
@@ -1,2395 +1,2395 @@
-<?php
-/**
- * TControl, TControlCollection, TEventParameter and INamingContainer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TAttributeCollection and TControlAdapter class
- */
-Prado::using('System.Collections.TAttributeCollection');
-Prado::using('System.Web.UI.TControlAdapter');
-
-/**
- * TControl class
- *
- * TControl is the base class for all components on a page hierarchy.
- * It implements the following features for UI-related functionalities:
- * - databinding feature
- * - parent and child relationship
- * - naming container and containee relationship
- * - viewstate and controlstate features
- * - rendering scheme
- * - control lifecycles
- *
- * A property can be data-bound with an expression. By calling {@link dataBind},
- * expressions bound to properties will be evaluated and the results will be
- * set to the corresponding properties.
- *
- * Parent and child relationship determines how the presentation of controls are
- * enclosed within each other. A parent will determine where to place
- * the presentation of its child controls. For example, a TPanel will enclose
- * all its child controls' presentation within a div html tag. A control's parent
- * can be obtained via {@link getParent Parent} property, and its
- * {@link getControls Controls} property returns a list of the control's children,
- * including controls and static texts. The property can be manipulated
- * like an array for adding or removing a child (see {@link TList} for more details).
- *
- * A naming container control implements INamingContainer and ensures that
- * its containee controls can be differentiated by their ID property values.
- * Naming container and containee realtionship specifies a protocol to uniquely
- * identify an arbitrary control on a page hierarchy by an ID path (concatenation
- * of all naming containers' IDs and the target control's ID).
- *
- * Viewstate and controlstate are two approaches to preserve state across
- * page postback requests. ViewState is mainly related with UI specific state
- * and can be disabled if not needed. ControlState represents crucial logic state
- * and cannot be disabled.
- *
- * A control is rendered via its {@link render()} method (the method is invoked
- * by the framework.) Descendant control classes may override this method for
- * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
- * which is responsible for rendering of children of the control.
- * Control's {@link getVisible Visible} property governs whether the control
- * should be rendered or not.
- *
- * Each control on a page will undergo a series of lifecycles, including
- * control construction, Init, Load, PreRender, Render, and OnUnload.
- * They work together with page lifecycles to process a page request.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControl extends TApplicationComponent implements IRenderable, IBindable
-{
- /**
- * format of control ID
- */
- const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
- /**
- * separator char between IDs in a UniqueID
- */
- const ID_SEPARATOR='$';
- /**
- * separator char between IDs in a ClientID
- */
- const CLIENT_ID_SEPARATOR='_';
- /**
- * prefix to an ID automatically generated
- */
- const AUTOMATIC_ID_PREFIX='ctl';
-
- /**
- * the stage of lifecycles that the control is currently at
- */
- const CS_CONSTRUCTED=0;
- const CS_CHILD_INITIALIZED=1;
- const CS_INITIALIZED=2;
- const CS_STATE_LOADED=3;
- const CS_LOADED=4;
- const CS_PRERENDERED=5;
-
- /**
- * State bits.
- */
- const IS_ID_SET=0x01;
- const IS_DISABLE_VIEWSTATE=0x02;
- const IS_SKIN_APPLIED=0x04;
- const IS_STYLESHEET_APPLIED=0x08;
- const IS_DISABLE_THEMING=0x10;
- const IS_CHILD_CREATED=0x20;
- const IS_CREATING_CHILD=0x40;
-
- /**
- * Indexes for the rare fields.
- * In order to save memory, rare fields will only be created if they are needed.
- */
- const RF_CONTROLS=0; // child controls
- const RF_CHILD_STATE=1; // child state field
- const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
- const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
- const RF_SKIN_ID=4; // skin ID
- const RF_DATA_BINDINGS=5; // data bindings
- const RF_EVENTS=6; // event handlers
- const RF_CONTROLSTATE=7; // controlstate
- const RF_NAMED_OBJECTS=8; // controls declared with ID on template
- const RF_ADAPTER=9; // adapter
- const RF_AUTO_BINDINGS=10; // auto data bindings
-
- /**
- * @var string control ID
- */
- private $_id='';
- /**
- * @var string control unique ID
- */
- private $_uid;
- /**
- * @var TControl parent of the control
- */
- private $_parent;
- /**
- * @var TPage page that the control resides in
- */
- private $_page;
- /**
- * @var TControl naming container of the control
- */
- private $_namingContainer;
- /**
- * @var TTemplateControl control whose template contains the control
- */
- private $_tplControl;
- /**
- * @var array viewstate data
- */
- private $_viewState=array();
- /**
- * @var array temporary state (usually set in template)
- */
- private $_tempState=array();
- /**
- * @var boolean whether we should keep state in viewstate
- */
- private $_trackViewState=true;
- /**
- * @var integer the current stage of the control lifecycles
- */
- private $_stage=0;
- /**
- * @var integer representation of the state bits
- */
- private $_flags=0;
- /**
- * @var array a collection of rare control data
- */
- private $_rf=array();
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- }
-
- /**
- * Returns a property value by name or a control by ID.
- * This overrides the parent implementation by allowing accessing
- * a control via its ID using the following syntax,
- * <code>
- * $menuBar=$this->menuBar;
- * </code>
- * Note, the control must be configured in the template
- * with explicit ID. If the name matches both a property and a control ID,
- * the control ID will take the precedence.
- *
- * @param string the property name or control ID
- * @return mixed the property value or the target control
- * @throws TInvalidOperationException if the property is not defined.
- * @see registerObject
- */
- public function __get($name)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- return $this->_rf[self::RF_NAMED_OBJECTS][$name];
- else
- return parent::__get($name);
- }
-
- /**
- * @return boolean whether there is an adapter for this control
- */
- public function getHasAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER]);
- }
-
- /**
- * @return TControlAdapter control adapter. Null if not exists.
- */
- public function getAdapter()
- {
- return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
- }
-
- /**
- * @param TControlAdapter control adapter
- */
- public function setAdapter(TControlAdapter $adapter)
- {
- $this->_rf[self::RF_ADAPTER]=$adapter;
- }
-
- /**
- * @return TControl the parent of this control
- */
- public function getParent()
- {
- return $this->_parent;
- }
-
- /**
- * @return TControl the naming container of this control
- */
- public function getNamingContainer()
- {
- if(!$this->_namingContainer && $this->_parent)
- {
- if($this->_parent instanceof INamingContainer)
- $this->_namingContainer=$this->_parent;
- else
- $this->_namingContainer=$this->_parent->getNamingContainer();
- }
- return $this->_namingContainer;
- }
-
- /**
- * @return TPage the page that contains this control
- */
- public function getPage()
- {
- if(!$this->_page)
- {
- if($this->_parent)
- $this->_page=$this->_parent->getPage();
- else if($this->_tplControl)
- $this->_page=$this->_tplControl->getPage();
- }
- return $this->_page;
- }
-
- /**
- * Sets the page for a control.
- * Only framework developers should use this method.
- * @param TPage the page that contains this control
- */
- public function setPage($page)
- {
- $this->_page=$page;
- }
-
- /**
- * Sets the control whose template contains this control.
- * Only framework developers should use this method.
- * @param TTemplateControl the control whose template contains this control
- */
- public function setTemplateControl($control)
- {
- $this->_tplControl=$control;
- }
-
- /**
- * @return TTemplateControl the control whose template contains this control
- */
- public function getTemplateControl()
- {
- if(!$this->_tplControl && $this->_parent)
- $this->_tplControl=$this->_parent->getTemplateControl();
- return $this->_tplControl;
- }
-
- /**
- * @return TTemplateControl the control whose template is loaded from
- * some external storage, such as file, db, and whose template ultimately
- * contains this control.
- */
- public function getSourceTemplateControl()
- {
- $control=$this;
- while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
- {
- if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
- return $control;
- }
- return $this->getPage();
- }
-
- /**
- * Gets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @return integer the lifecycle step the control is currently at.
- * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function getControlStage()
- {
- return $this->_stage;
- }
-
- /**
- * Sets the lifecycle step the control is currently at.
- * This method should only be used by control developers.
- * @param integer the lifecycle step the control is currently at.
- * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
- * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
- */
- protected function setControlStage($value)
- {
- $this->_stage=$value;
- }
-
- /**
- * Returns the id of the control.
- * Control ID can be either manually set or automatically generated.
- * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
- * @param boolean whether to hide automatically generated ID
- * @return string the ID of the control
- */
- public function getID($hideAutoID=true)
- {
- if($hideAutoID)
- return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
- else
- return $this->_id;
- }
-
- /**
- * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
- * @throws TInvalidDataValueException if ID is in a bad format
- */
- public function setID($id)
- {
- if(!preg_match(self::ID_FORMAT,$id))
- throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
- $this->_id=$id;
- $this->_flags |= self::IS_ID_SET;
- $this->clearCachedUniqueID($this instanceof INamingContainer);
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Returns a unique ID that identifies the control in the page hierarchy.
- * A unique ID is the contenation of all naming container controls' IDs and the control ID.
- * These IDs are separated by '$' character.
- * Control users should not rely on the specific format of UniqueID, however.
- * @return string a unique ID that identifies the control in the page hierarchy
- */
- public function getUniqueID()
- {
- if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
- {
- $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
- if($namingContainer=$this->getNamingContainer())
- {
- if($this->getPage()===$namingContainer)
- return ($this->_uid=$this->_id);
- else if(($prefix=$namingContainer->getUniqueID())==='')
- return $this->_id;
- else
- return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
- }
- else // no naming container
- return $this->_id;
- }
- else
- return $this->_uid;
- }
-
- /**
- * Sets input focus to this control.
- */
- public function focus()
- {
- $this->getPage()->setFocus($this);
- }
-
- /**
- * Returns the client ID of the control.
- * The client ID can be used to uniquely identify
- * the control in client-side scripts (such as JavaScript).
- * Do not rely on the explicit format of the return ID.
- * @return string the client ID of the control
- */
- public function getClientID()
- {
- return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * Converts a unique ID to a client ID.
- * @param string the unique ID of a control
- * @return string the client ID of the control
- */
- public static function convertUniqueIdToClientId($uniqueID)
- {
- return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
- }
-
- /**
- * @return string the skin ID of this control, '' if not set
- */
- public function getSkinID()
- {
- return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function setSkinID($value)
- {
- if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
- else
- $this->_rf[self::RF_SKIN_ID]=$value;
- }
-
- /**
- * @param string the skin ID of this control
- * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
- */
- public function getIsSkinApplied()
- {
- return ($this->_flags & self::IS_SKIN_APPLIED);
- }
-
- /**
- * @return boolean whether theming is enabled for this control.
- * The theming is enabled if the control and all its parents have it enabled.
- */
- public function getEnableTheming()
- {
- if($this->_flags & self::IS_DISABLE_THEMING)
- return false;
- else
- return $this->_parent?$this->_parent->getEnableTheming():true;
- }
-
- /**
- * @param boolean whether to enable theming
- * @throws TInvalidOperationException if this method is invoked after OnPreInit
- */
- public function setEnableTheming($value)
- {
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
- else if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_THEMING;
- else
- $this->_flags |= self::IS_DISABLE_THEMING;
- }
-
- /**
- * Returns custom data associated with this control.
- * A control may be associated with some custom data for various purposes.
- * For example, a button may be associated with a string to identify itself
- * in a generic OnClick event handler.
- * @return mixed custom data associated with this control. Defaults to null.
- */
- public function getCustomData()
- {
- return $this->getViewState('CustomData',null);
- }
-
- /**
- * Associates custom data with this control.
- * Note, the custom data must be serializable and unserializable.
- * @param mixed custom data
- */
- public function setCustomData($value)
- {
- $this->setViewState('CustomData',$value,null);
- }
-
- /**
- * @return boolean whether the control has child controls
- */
- public function getHasControls()
- {
- return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
- }
-
- /**
- * @return TControlCollection the child control collection
- */
- public function getControls()
- {
- if(!isset($this->_rf[self::RF_CONTROLS]))
- $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
- return $this->_rf[self::RF_CONTROLS];
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TControlCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
- }
-
- /**
- * Checks if a control is visible.
- * If parent check is required, then a control is visible only if the control
- * and all its ancestors are visible.
- * @param boolean whether the parents should also be checked if visible
- * @return boolean whether the control is visible (default=true).
- */
- public function getVisible($checkParents=true)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getVisible(false))
- return false;
- return true;
- }
- else
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the control is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a value indicating whether the control is enabled.
- * A control is enabled if it allows client user interaction.
- * If $checkParents is true, all parent controls will be checked,
- * and unless they are all enabled, false will be returned.
- * The property Enabled is mainly used for {@link TWebControl}
- * derived controls.
- * @param boolean whether the parents should also be checked enabled
- * @return boolean whether the control is enabled.
- */
- public function getEnabled($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control;$control=$control->_parent)
- if(!$control->getViewState('Enabled',true))
- return false;
- return true;
- }
- else
- return $this->getViewState('Enabled',true);
- }
-
- /**
- * @param boolean whether the control is to be enabled.
- */
- public function setEnabled($value)
- {
- $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the control has custom attributes
- */
- public function getHasAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->getCount()>0;
- else
- return false;
- }
-
- /**
- * Returns the list of custom attributes.
- * Custom attributes are name-value pairs that may be rendered
- * as HTML tags' attributes.
- * @return TAttributeCollection the list of custom attributes
- */
- public function getAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('Attributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->contains($name);
- else
- return false;
- }
-
- /**
- * @return string attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->itemAt($name);
- else
- return null;
- }
-
- /**
- * Sets a custom control attribute.
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, null if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->remove($name);
- else
- return null;
- }
-
- /**
- * @return boolean whether viewstate is enabled
- */
- public function getEnableViewState($checkParents=false)
- {
- if($checkParents)
- {
- for($control=$this;$control!==null;$control=$control->getParent())
- if($control->_flags & self::IS_DISABLE_VIEWSTATE)
- return false;
- return true;
- }
- else
- return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
- }
-
- /**
- * @param boolean set whether to enable viewstate
- */
- public function setEnableViewState($value)
- {
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
- else
- $this->_flags |= self::IS_DISABLE_VIEWSTATE;
- }
-
- /**
- * Returns a controlstate value.
- *
- * This function is mainly used in defining getter functions for control properties
- * that must be kept in controlstate.
- * @param string the name of the controlstate value to be returned
- * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
- * @return mixed the controlstate value corresponding to $key
- */
- protected function getControlState($key,$defaultValue=null)
- {
- return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
- }
-
- /**
- * Sets a controlstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in controlstate.
- * Make sure that the controlstate value must be serializable and unserializable.
- * @param string the name of the controlstate value
- * @param mixed the controlstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
- */
- protected function setControlState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- else
- $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
- }
-
- /**
- * Clears a controlstate value.
- * @param string the name of the controlstate value to be cleared
- */
- protected function clearControlState($key)
- {
- unset($this->_rf[self::RF_CONTROLSTATE][$key]);
- }
-
- /**
- * Sets a value indicating whether we should keep data in viewstate.
- * When it is false, data saved via setViewState() will not be persisted.
- * By default, it is true, meaning data will be persisted across postbacks.
- * @param boolean whether data should be persisted
- */
- public function trackViewState($enabled)
- {
- $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
- }
-
- /**
- * Returns a viewstate value.
- *
- * This function is very useful in defining getter functions for component properties
- * that must be kept in viewstate.
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- public function getViewState($key,$defaultValue=null)
- {
- if(isset($this->_viewState[$key]))
- return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
- else if(isset($this->_tempState[$key]))
- {
- if(is_object($this->_tempState[$key]) && $this->_trackViewState)
- $this->_viewState[$key]=$this->_tempState[$key];
- return $this->_tempState[$key];
- }
- else
- return $defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in viewstate.
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- public function setViewState($key,$value,$defaultValue=null)
- {
- if($this->_trackViewState)
- {
- $this->_viewState[$key]=$value;
- unset($this->_tempState[$key]);
- }
- else
- {
- unset($this->_viewState[$key]);
- $this->_tempState[$key]=$value;
- }
- }
-
- /**
- * Clears a viewstate value.
- * @param string the name of the viewstate value to be cleared
- */
- public function clearViewState($key)
- {
- unset($this->_viewState[$key]);
- unset($this->_tempState[$key]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function bindProperty($name,$expression)
- {
- $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
- }
-
- /**
- * Breaks the binding between a property (or property path) and an expression.
- * @param string the property name (or property path)
- */
- public function unbindProperty($name)
- {
- unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
- }
-
- /**
- * Sets up the binding between a property (or property path) and an expression.
- * Unlike regular databinding, the expression bound by this method
- * is automatically evaluated during {@link prerenderRecursive()}.
- * The context of the expression is the template control (or the control itself if it is a page).
- * @param string the property name, or property path
- * @param string the expression
- */
- public function autoBindProperty($name,$expression)
- {
- $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
- }
-
- /**
- * Performs the databinding for this control.
- */
- public function dataBind()
- {
- $this->dataBindProperties();
- $this->onDataBinding(null);
- $this->dataBindChildren();
- }
-
- /**
- * Databinding properties of the control.
- */
- protected function dataBindProperties()
- {
- Prado::trace("Data bind properties",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_DATA_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Auto databinding properties of the control.
- */
- protected function autoDataBindProperties()
- {
- if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
- {
- if(($context=$this->getTemplateControl())===null)
- $context=$this;
- foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
- $this->setSubProperty($property,$context->evaluateExpression($expression));
- }
- }
-
- /**
- * Databinding child controls.
- */
- protected function dataBindChildren()
- {
- Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
- if(isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof IBindable)
- $control->dataBind();
- }
- }
-
- /**
- * @return boolean whether child controls have been created
- */
- final protected function getChildControlsCreated()
- {
- return ($this->_flags & self::IS_CHILD_CREATED)!==0;
- }
-
- /**
- * Sets a value indicating whether child controls are created.
- * If false, any existing child controls will be cleared up.
- * @param boolean whether child controls are created
- */
- final protected function setChildControlsCreated($value)
- {
- if($value)
- $this->_flags |= self::IS_CHILD_CREATED;
- else
- {
- if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
- $this->getControls()->clear();
- $this->_flags &= ~self::IS_CHILD_CREATED;
- }
- }
-
- /**
- * Ensures child controls are created.
- * If child controls are not created yet, this method will invoke
- * {@link createChildControls} to create them.
- */
- public function ensureChildControls()
- {
- if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
- {
- try
- {
- $this->_flags |= self::IS_CREATING_CHILD;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->createChildControls();
- else
- $this->createChildControls();
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- }
- catch(Exception $e)
- {
- $this->_flags &= ~self::IS_CREATING_CHILD;
- $this->_flags |= self::IS_CHILD_CREATED;
- throw $e;
- }
- }
- }
-
- /**
- * Creates child controls.
- * This method can be overriden for controls who want to have their controls.
- * Do not call this method directly. Instead, call {@link ensureChildControls}
- * to ensure child controls are created only once.
- */
- public function createChildControls()
- {
- }
-
- /**
- * Finds a control by ID path within the current naming container.
- * The current naming container is either the control itself
- * if it implements {@link INamingContainer} or the control's naming container.
- * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
- * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
- * whose naming container is 'Item1' whose naming container is 'Repeater1'.
- * @param string ID of the control to be looked up
- * @return TControl|null the control found, null if not found
- * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
- */
- public function findControl($id)
- {
- $id=strtr($id,'.',self::ID_SEPARATOR);
- $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
- if(!$container || !$container->getHasControls())
- return null;
- if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
- {
- $container->_rf[self::RF_NAMED_CONTROLS]=array();
- $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
- }
- if(($pos=strpos($id,self::ID_SEPARATOR))===false)
- return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
- else
- {
- $cid=substr($id,0,$pos);
- $sid=substr($id,$pos+1);
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
- return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
- else
- return null;
- }
- }
-
- /**
- * Finds all child and grand-child controls that are of the specified type.
- * @param string the class name
- * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
- * @return array list of controls found
- */
- public function findControlsByType($type,$strict=true)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
- $controls[]=$control;
- if(($control instanceof TControl) && $control->getHasControls())
- $controls=array_merge($controls,$control->findControlsByType($type,$strict));
- }
- }
- return $controls;
- }
-
- /**
- * Finds all child and grand-child controls with the specified ID.
- * Note, this method is different from {@link findControl} in that
- * it searches through all controls that have this control as the ancestor
- * while {@link findcontrol} only searches through controls that have this
- * control as the direct naming container.
- * @param string the ID being looked for
- * @return array list of controls found
- */
- public function findControlsByID($id)
- {
- $controls=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id===$id)
- $controls[]=$control;
- $controls=array_merge($controls,$control->findControlsByID($id));
- }
- }
- }
- return $controls;
- }
-
- /**
- * Resets the control as a naming container.
- * Only framework developers should use this method.
- */
- public function clearNamingContainer()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
- $this->clearNameTable();
- }
-
- /**
- * Registers an object by a name.
- * A registered object can be accessed like a public member variable.
- * This method should only be used by framework and control developers.
- * @param string name of the object
- * @param object object to be declared
- * @see __get
- */
- public function registerObject($name,$object)
- {
- if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
- throw new TInvalidOperationException('control_object_reregistered',$name);
- $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
- }
-
- /**
- * Unregisters an object by name.
- * @param string name of the object
- * @see registerObject
- */
- public function unregisterObject($name)
- {
- unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean whether an object has been registered with the name
- * @see registerObject
- */
- public function isObjectRegistered($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
- }
-
- /**
- * @return boolean true if the child control has been initialized.
- */
- public function getHasChildInitialized()
- {
- return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
- }
-
- /**
- * @return boolean true if the onInit event has raised.
- */
- public function getHasInitialized()
- {
- return $this->getControlStage() >= self::CS_INITIALIZED;
- }
-
- /**
- * @return boolean true if the control has loaded post data.
- */
- public function getHasLoadedPostData()
- {
- return $this->getControlStage() >= self::CS_STATE_LOADED;
- }
-
- /**
- * @return boolean true if the onLoad event has raised.
- */
- public function getHasLoaded()
- {
- return $this->getControlStage() >= self::CS_LOADED;
- }
-
- /**
- * @return boolean true if onPreRender event has raised.
- */
- public function getHasPreRendered()
- {
- return $this->getControlStage() >= self::CS_PRERENDERED;
- }
-
- /**
- * Returns the named registered object.
- * A component with explicit ID on a template will be registered to
- * the template owner. This method allows you to obtain this component
- * with the ID.
- * @return mixed the named registered object. Null if object is not found.
- */
- public function getRegisteredObject($name)
- {
- return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
- }
-
- /**
- * @return boolean whether body contents are allowed for this control. Defaults to true.
- */
- public function getAllowChildControls()
- {
- return true;
- }
-
- /**
- * Adds the object instantiated on a template to the child control collection.
- * This method overrides the parent implementation.
- * Only framework developers and control developers should use this method.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- $this->getControls()->add($object);
- }
-
- /**
- * Clears up the child state data.
- * After a control loads its state, those state that do not belong to
- * any existing child controls are stored as child state.
- * This method will remove these state.
- * Only frameworker developers and control developers should use this method.
- */
- final protected function clearChildState()
- {
- unset($this->_rf[self::RF_CHILD_STATE]);
- }
-
- /**
- * @param TControl the potential ancestor control
- * @return boolean if the control is a descendent (parent, parent of parent, etc.)
- * of the specified control
- */
- final protected function isDescendentOf($ancestor)
- {
- $control=$this;
- while($control!==$ancestor && $control->_parent)
- $control=$control->_parent;
- return $control===$ancestor;
- }
-
- /**
- * Adds a control into the child collection of the control.
- * Control lifecycles will be caught up during the addition.
- * Only framework developers should use this method.
- * @param TControl the new child control
- */
- public function addedControl($control)
- {
- if($control->_parent)
- $control->_parent->getControls()->remove($control);
- $control->_parent=$this;
- $control->_page=$this->getPage();
- $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
- if($namingContainer)
- {
- $control->_namingContainer=$namingContainer;
- if($control->_id==='')
- $control->generateAutomaticID();
- else
- $namingContainer->clearNameTable();
- $control->clearCachedUniqueID($control instanceof INamingContainer);
- }
-
- if($this->_stage>=self::CS_CHILD_INITIALIZED)
- {
- $control->initRecursive($namingContainer);
- if($this->_stage>=self::CS_STATE_LOADED)
- {
- if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
- {
- $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
- unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
- }
- else
- $state=null;
- $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if($this->_stage>=self::CS_LOADED)
- {
- $control->loadRecursive();
- if($this->_stage>=self::CS_PRERENDERED)
- $control->preRenderRecursive();
- }
- }
- }
- }
-
- /**
- * Removes a control from the child collection of the control.
- * Only framework developers should use this method.
- * @param TControl the child control removed
- */
- public function removedControl($control)
- {
- if($this->_namingContainer)
- $this->_namingContainer->clearNameTable();
- $control->unloadRecursive();
- $control->_parent=null;
- $control->_page=null;
- $control->_namingContainer=null;
- $control->_tplControl=null;
- //$control->_stage=self::CS_CONSTRUCTED;
- if(!($control->_flags & self::IS_ID_SET))
- $control->_id='';
- else
- unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
- $control->clearCachedUniqueID(true);
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->getHasControls())
- {
- if($this instanceof INamingContainer)
- $namingContainer=$this;
- $page=$this->getPage();
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->_namingContainer=$namingContainer;
- $control->_page=$page;
- if($control->_id==='' && $namingContainer)
- $control->generateAutomaticID();
- $control->initRecursive($namingContainer);
- }
- }
- }
- if($this->_stage<self::CS_INITIALIZED)
- {
- $this->_stage=self::CS_CHILD_INITIALIZED;
- if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
- {
- $page->applyControlSkin($this);
- $this->_flags |= self::IS_SKIN_APPLIED;
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onInit(null);
- else
- $this->onInit(null);
- $this->_stage=self::CS_INITIALIZED;
- }
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function loadRecursive()
- {
- if($this->_stage<self::CS_LOADED)
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onLoad(null);
- else
- $this->onLoad(null);
- }
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->loadRecursive();
- }
- }
- if($this->_stage<self::CS_LOADED)
- $this->_stage=self::CS_LOADED;
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function preRenderRecursive()
- {
- $this->autoDataBindProperties();
-
- if($this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onPreRender(null);
- else
- $this->onPreRender(null);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->preRenderRecursive();
- else if($control instanceof TCompositeLiteral)
- $control->evaluateDynamicContent();
- }
- }
- $this->addToPostDataLoader();
- }
- $this->_stage=self::CS_PRERENDERED;
- }
-
- /**
- * Add controls implementing IPostBackDataHandler to post data loaders.
- */
- protected function addToPostDataLoader()
- {
- if($this instanceof IPostBackDataHandler)
- $this->getPage()->registerPostDataLoader($this);
- }
-
- /**
- * Performs the Unload step for the control and all its child controls.
- * Only framework developers should use this method.
- */
- protected function unloadRecursive()
- {
- if(!($this->_flags & self::IS_ID_SET))
- $this->_id='';
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->unloadRecursive();
- }
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->onUnload(null);
- else
- $this->onUnload(null);
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * The method raises 'OnInit' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->raiseEvent('OnInit',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * The method raises 'OnLoad' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->raiseEvent('OnLoad',$this,$param);
- }
-
- /**
- * Raises 'OnDataBinding' event.
- * This method is invoked when {@link dataBind} is invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onDataBinding($param)
- {
- Prado::trace("onDataBinding()",'System.Web.UI.TControl');
- $this->raiseEvent('OnDataBinding',$this,$param);
- }
-
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * The method raises 'OnUnload' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->raiseEvent('OnUnload',$this,$param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * The method raises 'OnPreRender' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->raiseEvent('OnPreRender',$this,$param);
- }
-
- /**
- * Invokes the parent's bubbleEvent method.
- * A control who wants to bubble an event must call this method in its onEvent method.
- * @param TControl sender of the event
- * @param TEventParameter event parameter
- * @see bubbleEvent
- */
- protected function raiseBubbleEvent($sender,$param)
- {
- $control=$this;
- while($control=$control->_parent)
- {
- if($control->bubbleEvent($sender,$param))
- break;
- }
- }
-
- /**
- * This method responds to a bubbled event.
- * This method should be overriden to provide customized response to a bubbled event.
- * Check the type of event parameter to determine what event is bubbled currently.
- * @param TControl sender of the event
- * @param TEventParameter event parameters
- * @return boolean true if the event bubbling is handled and no more bubbling.
- * @see raiseBubbleEvent
- */
- public function bubbleEvent($sender,$param)
- {
- return false;
- }
-
- /**
- * Broadcasts an event.
- * The event will be sent to all controls on the current page hierarchy.
- * If a control defines the event, the event will be raised for the control.
- * If a control implements {@link IBroadcastEventReceiver}, its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
- * be invoked which gives the control a chance to respond to the event.
- * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
- * event will have this event raised, and all controls implementing
- * {@link IBroadcastEventReceiver} will also have its
- * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
- * invoked.
- * @param string name of the broadcast event
- * @param TControl sender of this event
- * @param TEventParameter event parameter
- */
- public function broadcastEvent($name,$sender,$param)
- {
- $rootControl=(($page=$this->getPage())===null)?$this:$page;
- $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
- }
-
- /**
- * Recursively broadcasts an event.
- * This method should only be used by framework developers.
- * @param string name of the broadcast event
- * @param TControl sender of the event
- * @param TBroadcastEventParameter event parameter
- */
- private function broadcastEventInternal($name,$sender,$param)
- {
- if($this->hasEvent($name))
- $this->raiseEvent($name,$sender,$param->getParameter());
- if($this instanceof IBroadcastEventReceiver)
- $this->broadcastEventReceived($sender,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $control->broadcastEventInternal($name,$sender,$param);
- }
- }
- }
-
- /**
- * Traverse the whole control hierarchy rooted at this control.
- * Callback function may be invoked for each control being visited.
- * A pre-callback is invoked before traversing child controls;
- * A post-callback is invoked after traversing child controls.
- * Callback functions can be global functions or class methods.
- * They must be of the following signature:
- * <code>
- * function callback_func($control,$param) {...}
- * </code>
- * where $control refers to the control being visited and $param
- * is the parameter that is passed originally when calling this traverse function.
- *
- * @param mixed parameter to be passed to callbacks for each control
- * @param callback callback invoked before traversing child controls. If null, it is ignored.
- * @param callback callback invoked after traversing child controls. If null, it is ignored.
- */
- protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
- {
- if($preCallback!==null)
- call_user_func($preCallback,$this,$param);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- $control->traverseChildControls($param,$preCallback,$postCallback);
- }
- }
- }
- if($postCallback!==null)
- call_user_func($postCallback,$this,$param);
- }
-
- /**
- * Renders the control.
- * Only when the control is visible will the control be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderControl($writer)
- {
- if($this instanceof IActiveControl || $this->getVisible(false))
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->render($writer);
- else
- $this->render($writer);
- }
- }
-
- /**
- * Renders the control.
- * This method is invoked by {@link renderControl} when the control is visible.
- * You can override this method to provide customized rendering of the control.
- * By default, the control simply renders all its child contents.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $this->renderChildren($writer);
- }
-
- /**
- * Renders the children of the control.
- * This method iterates through all child controls and static text strings
- * and renders them in order.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderChildren($writer)
- {
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if(is_string($control))
- $writer->write($control);
- else if($control instanceof TControl)
- $control->renderControl($writer);
- else if($control instanceof IRenderable)
- $control->render($writer);
- }
- }
- }
-
- /**
- * This method is invoked when control state is to be saved.
- * You can override this method to do last step state saving.
- * Parent implementation must be invoked.
- */
- public function saveState()
- {
- }
-
- /**
- * This method is invoked right after the control has loaded its state.
- * You can override this method to initialize data from the control state.
- * Parent implementation must be invoked.
- */
- public function loadState()
- {
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- if(is_array($state))
- {
- // A null state means the stateful properties all take default values.
- // So if the state is enabled, we have to assign the null value.
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- if(isset($state[1]))
- {
- $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
- unset($state[1]);
- }
- else
- unset($this->_rf[self::RF_CONTROLSTATE]);
- if($needViewState)
- {
- if(isset($state[0]))
- $this->_viewState=&$state[0];
- else
- $this->_viewState=array();
- }
- unset($state[0]);
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- {
- if(isset($state[$control->_id]))
- {
- $control->loadStateRecursive($state[$control->_id],$needViewState);
- unset($state[$control->_id]);
- }
- }
- }
- }
- if(!empty($state))
- $this->_rf[self::RF_CHILD_STATE]=&$state;
- }
- $this->_stage=self::CS_STATE_LOADED;
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->loadState();
- else
- $this->loadState();
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if(isset($this->_rf[self::RF_ADAPTER]))
- $this->_rf[self::RF_ADAPTER]->saveState();
- else
- $this->saveState();
- $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
- $state=array();
- if($this->getHasControls())
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- {
- if($control instanceof TControl)
- $state[$control->_id]=&$control->saveStateRecursive($needViewState);
- }
- }
- if($needViewState && !empty($this->_viewState))
- $state[0]=&$this->_viewState;
- if(isset($this->_rf[self::RF_CONTROLSTATE]))
- $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
- return $state;
- }
-
- /**
- * Applies a stylesheet skin to a control.
- * @param TPage the page containing the control
- * @throws TInvalidOperationException if the stylesheet skin is applied already
- */
- public function applyStyleSheetSkin($page)
- {
- if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
- {
- $page->applyControlStyleSheet($this);
- $this->_flags |= self::IS_STYLESHEET_APPLIED;
- }
- else if($this->_flags & self::IS_STYLESHEET_APPLIED)
- throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
- }
-
- /**
- * Clears the cached UniqueID.
- * If $recursive=true, all children's cached UniqueID will be cleared as well.
- * @param boolean whether the clearing is recursive.
- */
- private function clearCachedUniqueID($recursive)
- {
- if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
- {
- foreach($this->_rf[self::RF_CONTROLS] as $control)
- if($control instanceof TControl)
- $control->clearCachedUniqueID($recursive);
- }
- $this->_uid=null;
- }
-
- /**
- * Generates an automatic ID for the control.
- */
- private function generateAutomaticID()
- {
- $this->_flags &= ~self::IS_ID_SET;
- if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
- $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
- $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
- $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
- $this->_namingContainer->clearNameTable();
- }
-
- /**
- * Clears the list of the controls whose IDs are managed by the specified naming container.
- */
- private function clearNameTable()
- {
- unset($this->_rf[self::RF_NAMED_CONTROLS]);
- }
-
- /**
- * Updates the list of the controls whose IDs are managed by the specified naming container.
- * @param TControl the naming container
- * @param TControlCollection list of controls
- * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
- */
- private function fillNameTable($container,$controls)
- {
- foreach($controls as $control)
- {
- if($control instanceof TControl)
- {
- if($control->_id!=='')
- {
- if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
- throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
- else
- $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
- }
- if(!($control instanceof INamingContainer) && $control->getHasControls())
- $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
- }
- }
- }
-}
-
-
-/**
- * TControlCollection class
- *
- * TControlCollection implements a collection that enables
- * controls to maintain a list of their child controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControlCollection extends TList
-{
- /**
- * the control that owns this collection.
- * @var TControl
- */
- private $_o;
-
- /**
- * Constructor.
- * @param TControl the control that owns this collection.
- * @param boolean whether the list is read-only
- */
- public function __construct(TControl $owner,$readOnly=false)
- {
- $this->_o=$owner;
- parent::__construct(null,$readOnly);
- }
-
- /**
- * @return TControl the control that owns this collection.
- */
- protected function getOwner()
- {
- return $this->_o;
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added child control.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- {
- parent::insertAt($index,$item);
- $this->_o->addedControl($item);
- }
- else if(is_string($item) || ($item instanceof IRenderable))
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('controlcollection_control_required');
- }
-
- /**
- * Removes an item at the specified position.
- * This overrides the parent implementation by performing additional
- * cleanup work when removing a child control.
- * @param integer the index of the item to be removed.
- * @return mixed the removed item.
- */
- public function removeAt($index)
- {
- $item=parent::removeAt($index);
- if($item instanceof TControl)
- $this->_o->removedControl($item);
- return $item;
- }
-
- /**
- * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer}
- */
- public function clear()
- {
- parent::clear();
- if($this->_o instanceof INamingContainer)
- $this->_o->clearNamingContainer();
- }
-}
-
-/**
- * TEmptyControlCollection class
- *
- * TEmptyControlCollection implements an empty control list that prohibits adding
- * controls to it. This is useful for controls that do not allow child controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TEmptyControlCollection extends TControlCollection
-{
- /**
- * Constructor.
- * @param TControl the control that owns this collection.
- */
- public function __construct(TControl $owner)
- {
- parent::__construct($owner,true);
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by ignoring new addition.
- * @param integer the speicified position.
- * @param mixed new item
- */
- public function insertAt($index,$item)
- {
- if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case
- parent::insertAt($index,$item); // this will generate an exception in parent implementation
- }
-}
-
-/**
- * INamingContainer interface.
- * INamingContainer marks a control as a naming container.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface INamingContainer
-{
-}
-
-/**
- * IPostBackEventHandler interface
- *
- * If a control wants to respond to postback event, it must implement this interface.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IPostBackEventHandler
-{
- /**
- * Raises postback event.
- * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand)
- * indicating the component is responsible for the postback event.
- * @param string the parameter associated with the postback event
- */
- public function raisePostBackEvent($param);
-}
-
-/**
- * IPostBackDataHandler interface
- *
- * If a control wants to load post data, it must implement this interface.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IPostBackDataHandler
-{
- /**
- * Loads user input data.
- * The implementation of this function can use $values[$key] to get the user input
- * data that are meant for the particular control.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values);
- /**
- * Raises postdata changed event.
- * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged)
- * indicating the control data is changed.
- */
- public function raisePostDataChangedEvent();
- /**
- * @return boolean whether postback causes the data change. Defaults to false for non-postback state.
- */
- public function getDataChanged();
-}
-
-
-/**
- * IValidator interface
- *
- * If a control wants to validate user input, it must implement this interface.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IValidator
-{
- /**
- * Validates certain data.
- * The implementation of this function should validate certain data
- * (e.g. data entered into TTextBox control).
- * @return boolean whether the data passes the validation
- */
- public function validate();
- /**
- * @return boolean whether the previous {@link validate()} is successful.
- */
- public function getIsValid();
- /**
- * @param boolean whether the validator validates successfully
- */
- public function setIsValid($value);
- /**
- * @return string error message during last validate
- */
- public function getErrorMessage();
- /**
- * @param string error message for the validation
- */
- public function setErrorMessage($value);
-}
-
-
-/**
- * IValidatable interface
- *
- * If a control wants to be validated by a validator, it must implement this interface.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IValidatable
-{
- /**
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue();
- /**
- * @return boolean wether this control's validators validated successfully (must default to true)
- */
- public function getIsValid();
- /**
- * @return boolean wether this control's validators validated successfully
- */
- public function setIsValid($value);
-}
-
-/**
- * IBroadcastEventReceiver interface
- *
- * If a control wants to check broadcast event, it must implement this interface.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IBroadcastEventReceiver
-{
- /**
- * Handles broadcast event.
- * This method is invoked automatically when an event is broadcasted.
- * Within this method, you may check the event name given in
- * the event parameter to determine whether you should respond to
- * this event.
- * @param TControl sender of the event
- * @param TBroadCastEventParameter event parameter
- */
- public function broadcastEventReceived($sender,$param);
-}
-
-/**
- * ITheme interface.
- *
- * This interface must be implemented by theme.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface ITheme
-{
- /**
- * Applies this theme to the specified control.
- * @param TControl the control to be applied with this theme
- */
- public function applySkin($control);
-}
-
-/**
- * ITemplate interface
- *
- * ITemplate specifies the interface for classes encapsulating
- * parsed template structures.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface ITemplate
-{
- /**
- * Instantiates the template.
- * Content in the template will be instantiated as components and text strings
- * and passed to the specified parent control.
- * @param TControl the parent control
- */
- public function instantiateIn($parent);
-}
-
-/**
- * IButtonControl interface
- *
- * IButtonControl specifies the common properties and events that must
- * be implemented by a button control, such as {@link TButton}, {@link TLinkButton},
- * {@link TImageButton}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-interface IButtonControl
-{
- /**
- * @return string caption of the button
- */
- public function getText();
-
- /**
- * @param string caption of the button
- */
- public function setText($value);
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation
- */
- public function getCausesValidation();
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value);
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName();
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value);
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter();
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value);
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup();
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value);
-
- /**
- * Raises <b>OnClick</b> event.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param);
-
- /**
- * Raises <b>OnCommand</b> event.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param);
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value);
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton();
-}
-
-/**
- * ISurroundable interface
- *
- * Identifies controls that may create an additional surrounding tag. The id of the
- * tag can be obtained with {@link getSurroundingTagID}.
- *
- * @package System.Web.UI
- * @since 3.1.2
- */
-interface ISurroundable
-{
- /**
- * @return string the id of the embedding tag of the control or the control's clientID if not surrounded
- */
- public function getSurroundingTagID();
-}
-
-/**
- * TBroadcastEventParameter class
- *
- * TBroadcastEventParameter encapsulates the parameter data for
- * events that are broadcasted. The name of of the event is specified via
- * {@link setName Name} property while the event parameter is via
- * {@link setParameter Parameter} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TBroadcastEventParameter extends TEventParameter
-{
- private $_name;
- private $_param;
-
- /**
- * Constructor.
- * @param string name of the broadcast event
- * @param mixed parameter of the broadcast event
- */
- public function __construct($name='',$parameter=null)
- {
- $this->_name=$name;
- $this->_param=$parameter;
- }
-
- /**
- * @return string name of the broadcast event
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string name of the broadcast event
- */
- public function setName($value)
- {
- $this->_name=$value;
- }
-
- /**
- * @return mixed parameter of the broadcast event
- */
- public function getParameter()
- {
- return $this->_param;
- }
-
- /**
- * @param mixed parameter of the broadcast event
- */
- public function setParameter($value)
- {
- $this->_param=$value;
- }
-}
-
-/**
- * TCommandEventParameter class
- *
- * TCommandEventParameter encapsulates the parameter data for <b>Command</b>
- * event of button controls. You can access the name of the command via
- * {@link getCommandName CommandName} property, and the parameter carried
- * with the command via {@link getCommandParameter CommandParameter} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCommandEventParameter extends TEventParameter
-{
- private $_name;
- private $_param;
-
- /**
- * Constructor.
- * @param string name of the command
- * @param string parameter of the command
- */
- public function __construct($name='',$parameter='')
- {
- $this->_name=$name;
- $this->_param=$parameter;
- }
-
- /**
- * @return string name of the command
- */
- public function getCommandName()
- {
- return $this->_name;
- }
-
- /**
- * @return string parameter of the command
- */
- public function getCommandParameter()
- {
- return $this->_param;
- }
-}
-
-
-/**
- * TCompositeLiteral class
- *
- * TCompositeLiteral is used internally by {@link TTemplate} for representing
- * consecutive static strings, expressions and statements.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TCompositeLiteral extends TComponent implements IRenderable, IBindable
-{
- const TYPE_EXPRESSION=0;
- const TYPE_STATEMENTS=1;
- const TYPE_DATABINDING=2;
- private $_container=null;
- private $_items=array();
- private $_expressions=array();
- private $_statements=array();
- private $_bindings=array();
-
- /**
- * Constructor.
- * @param array list of items to be represented by TCompositeLiteral
- */
- public function __construct($items)
- {
- $this->_items=array();
- $this->_expressions=array();
- $this->_statements=array();
- foreach($items as $id=>$item)
- {
- if(is_array($item))
- {
- if($item[0]===self::TYPE_EXPRESSION)
- $this->_expressions[$id]=$item[1];
- else if($item[0]===self::TYPE_STATEMENTS)
- $this->_statements[$id]=$item[1];
- else if($item[0]===self::TYPE_DATABINDING)
- $this->_bindings[$id]=$item[1];
- $this->_items[$id]='';
- }
- else
- $this->_items[$id]=$item;
- }
- }
-
- /**
- * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function getContainer()
- {
- return $this->_container;
- }
-
- /**
- * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
- */
- public function setContainer(TComponent $value)
- {
- $this->_container=$value;
- }
-
- /**
- * Evaluates the expressions and/or statements in the component.
- */
- public function evaluateDynamicContent()
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_expressions as $id=>$expression)
- $this->_items[$id]=$context->evaluateExpression($expression);
- foreach($this->_statements as $id=>$statement)
- $this->_items[$id]=$context->evaluateStatements($statement);
- }
-
- /**
- * Performs databindings.
- * This method is required by {@link IBindable}
- */
- public function dataBind()
- {
- $context=$this->_container===null?$this:$this->_container;
- foreach($this->_bindings as $id=>$binding)
- $this->_items[$id]=$context->evaluateExpression($binding);
- }
-
- /**
- * Renders the content stored in this component.
- * This method is required by {@link IRenderable}
- * @param ITextWriter
- */
- public function render($writer)
- {
- $writer->write(implode('',$this->_items));
- }
-}
-
-?>
+<?php
+/**
+ * TControl, TControlCollection, TEventParameter and INamingContainer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TAttributeCollection and TControlAdapter class
+ */
+Prado::using('System.Collections.TAttributeCollection');
+Prado::using('System.Web.UI.TControlAdapter');
+
+/**
+ * TControl class
+ *
+ * TControl is the base class for all components on a page hierarchy.
+ * It implements the following features for UI-related functionalities:
+ * - databinding feature
+ * - parent and child relationship
+ * - naming container and containee relationship
+ * - viewstate and controlstate features
+ * - rendering scheme
+ * - control lifecycles
+ *
+ * A property can be data-bound with an expression. By calling {@link dataBind},
+ * expressions bound to properties will be evaluated and the results will be
+ * set to the corresponding properties.
+ *
+ * Parent and child relationship determines how the presentation of controls are
+ * enclosed within each other. A parent will determine where to place
+ * the presentation of its child controls. For example, a TPanel will enclose
+ * all its child controls' presentation within a div html tag. A control's parent
+ * can be obtained via {@link getParent Parent} property, and its
+ * {@link getControls Controls} property returns a list of the control's children,
+ * including controls and static texts. The property can be manipulated
+ * like an array for adding or removing a child (see {@link TList} for more details).
+ *
+ * A naming container control implements INamingContainer and ensures that
+ * its containee controls can be differentiated by their ID property values.
+ * Naming container and containee realtionship specifies a protocol to uniquely
+ * identify an arbitrary control on a page hierarchy by an ID path (concatenation
+ * of all naming containers' IDs and the target control's ID).
+ *
+ * Viewstate and controlstate are two approaches to preserve state across
+ * page postback requests. ViewState is mainly related with UI specific state
+ * and can be disabled if not needed. ControlState represents crucial logic state
+ * and cannot be disabled.
+ *
+ * A control is rendered via its {@link render()} method (the method is invoked
+ * by the framework.) Descendant control classes may override this method for
+ * customized rendering. By default, {@link render()} invokes {@link renderChildren()}
+ * which is responsible for rendering of children of the control.
+ * Control's {@link getVisible Visible} property governs whether the control
+ * should be rendered or not.
+ *
+ * Each control on a page will undergo a series of lifecycles, including
+ * control construction, Init, Load, PreRender, Render, and OnUnload.
+ * They work together with page lifecycles to process a page request.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControl extends TApplicationComponent implements IRenderable, IBindable
+{
+ /**
+ * format of control ID
+ */
+ const ID_FORMAT='/^[a-zA-Z_]\\w*$/';
+ /**
+ * separator char between IDs in a UniqueID
+ */
+ const ID_SEPARATOR='$';
+ /**
+ * separator char between IDs in a ClientID
+ */
+ const CLIENT_ID_SEPARATOR='_';
+ /**
+ * prefix to an ID automatically generated
+ */
+ const AUTOMATIC_ID_PREFIX='ctl';
+
+ /**
+ * the stage of lifecycles that the control is currently at
+ */
+ const CS_CONSTRUCTED=0;
+ const CS_CHILD_INITIALIZED=1;
+ const CS_INITIALIZED=2;
+ const CS_STATE_LOADED=3;
+ const CS_LOADED=4;
+ const CS_PRERENDERED=5;
+
+ /**
+ * State bits.
+ */
+ const IS_ID_SET=0x01;
+ const IS_DISABLE_VIEWSTATE=0x02;
+ const IS_SKIN_APPLIED=0x04;
+ const IS_STYLESHEET_APPLIED=0x08;
+ const IS_DISABLE_THEMING=0x10;
+ const IS_CHILD_CREATED=0x20;
+ const IS_CREATING_CHILD=0x40;
+
+ /**
+ * Indexes for the rare fields.
+ * In order to save memory, rare fields will only be created if they are needed.
+ */
+ const RF_CONTROLS=0; // child controls
+ const RF_CHILD_STATE=1; // child state field
+ const RF_NAMED_CONTROLS=2; // list of controls whose namingcontainer is this control
+ const RF_NAMED_CONTROLS_ID=3; // counter for automatic id
+ const RF_SKIN_ID=4; // skin ID
+ const RF_DATA_BINDINGS=5; // data bindings
+ const RF_EVENTS=6; // event handlers
+ const RF_CONTROLSTATE=7; // controlstate
+ const RF_NAMED_OBJECTS=8; // controls declared with ID on template
+ const RF_ADAPTER=9; // adapter
+ const RF_AUTO_BINDINGS=10; // auto data bindings
+
+ /**
+ * @var string control ID
+ */
+ private $_id='';
+ /**
+ * @var string control unique ID
+ */
+ private $_uid;
+ /**
+ * @var TControl parent of the control
+ */
+ private $_parent;
+ /**
+ * @var TPage page that the control resides in
+ */
+ private $_page;
+ /**
+ * @var TControl naming container of the control
+ */
+ private $_namingContainer;
+ /**
+ * @var TTemplateControl control whose template contains the control
+ */
+ private $_tplControl;
+ /**
+ * @var array viewstate data
+ */
+ private $_viewState=array();
+ /**
+ * @var array temporary state (usually set in template)
+ */
+ private $_tempState=array();
+ /**
+ * @var boolean whether we should keep state in viewstate
+ */
+ private $_trackViewState=true;
+ /**
+ * @var integer the current stage of the control lifecycles
+ */
+ private $_stage=0;
+ /**
+ * @var integer representation of the state bits
+ */
+ private $_flags=0;
+ /**
+ * @var array a collection of rare control data
+ */
+ private $_rf=array();
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ }
+
+ /**
+ * Returns a property value by name or a control by ID.
+ * This overrides the parent implementation by allowing accessing
+ * a control via its ID using the following syntax,
+ * <code>
+ * $menuBar=$this->menuBar;
+ * </code>
+ * Note, the control must be configured in the template
+ * with explicit ID. If the name matches both a property and a control ID,
+ * the control ID will take the precedence.
+ *
+ * @param string the property name or control ID
+ * @return mixed the property value or the target control
+ * @throws TInvalidOperationException if the property is not defined.
+ * @see registerObject
+ */
+ public function __get($name)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ return $this->_rf[self::RF_NAMED_OBJECTS][$name];
+ else
+ return parent::__get($name);
+ }
+
+ /**
+ * @return boolean whether there is an adapter for this control
+ */
+ public function getHasAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER]);
+ }
+
+ /**
+ * @return TControlAdapter control adapter. Null if not exists.
+ */
+ public function getAdapter()
+ {
+ return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null;
+ }
+
+ /**
+ * @param TControlAdapter control adapter
+ */
+ public function setAdapter(TControlAdapter $adapter)
+ {
+ $this->_rf[self::RF_ADAPTER]=$adapter;
+ }
+
+ /**
+ * @return TControl the parent of this control
+ */
+ public function getParent()
+ {
+ return $this->_parent;
+ }
+
+ /**
+ * @return TControl the naming container of this control
+ */
+ public function getNamingContainer()
+ {
+ if(!$this->_namingContainer && $this->_parent)
+ {
+ if($this->_parent instanceof INamingContainer)
+ $this->_namingContainer=$this->_parent;
+ else
+ $this->_namingContainer=$this->_parent->getNamingContainer();
+ }
+ return $this->_namingContainer;
+ }
+
+ /**
+ * @return TPage the page that contains this control
+ */
+ public function getPage()
+ {
+ if(!$this->_page)
+ {
+ if($this->_parent)
+ $this->_page=$this->_parent->getPage();
+ else if($this->_tplControl)
+ $this->_page=$this->_tplControl->getPage();
+ }
+ return $this->_page;
+ }
+
+ /**
+ * Sets the page for a control.
+ * Only framework developers should use this method.
+ * @param TPage the page that contains this control
+ */
+ public function setPage($page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Sets the control whose template contains this control.
+ * Only framework developers should use this method.
+ * @param TTemplateControl the control whose template contains this control
+ */
+ public function setTemplateControl($control)
+ {
+ $this->_tplControl=$control;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template contains this control
+ */
+ public function getTemplateControl()
+ {
+ if(!$this->_tplControl && $this->_parent)
+ $this->_tplControl=$this->_parent->getTemplateControl();
+ return $this->_tplControl;
+ }
+
+ /**
+ * @return TTemplateControl the control whose template is loaded from
+ * some external storage, such as file, db, and whose template ultimately
+ * contains this control.
+ */
+ public function getSourceTemplateControl()
+ {
+ $control=$this;
+ while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null)
+ {
+ if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl())
+ return $control;
+ }
+ return $this->getPage();
+ }
+
+ /**
+ * Gets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @return integer the lifecycle step the control is currently at.
+ * The value can be CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function getControlStage()
+ {
+ return $this->_stage;
+ }
+
+ /**
+ * Sets the lifecycle step the control is currently at.
+ * This method should only be used by control developers.
+ * @param integer the lifecycle step the control is currently at.
+ * Valid values include CS_CONSTRUCTED, CS_CHILD_INITIALIZED, CS_INITIALIZED,
+ * CS_STATE_LOADED, CS_LOADED, CS_PRERENDERED.
+ */
+ protected function setControlStage($value)
+ {
+ $this->_stage=$value;
+ }
+
+ /**
+ * Returns the id of the control.
+ * Control ID can be either manually set or automatically generated.
+ * If $hideAutoID is true, automatically generated ID will be returned as an empty string.
+ * @param boolean whether to hide automatically generated ID
+ * @return string the ID of the control
+ */
+ public function getID($hideAutoID=true)
+ {
+ if($hideAutoID)
+ return ($this->_flags & self::IS_ID_SET) ? $this->_id : '';
+ else
+ return $this->_id;
+ }
+
+ /**
+ * @param string the new control ID. The value must consist of word characters [a-zA-Z0-9_] only
+ * @throws TInvalidDataValueException if ID is in a bad format
+ */
+ public function setID($id)
+ {
+ if(!preg_match(self::ID_FORMAT,$id))
+ throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id);
+ $this->_id=$id;
+ $this->_flags |= self::IS_ID_SET;
+ $this->clearCachedUniqueID($this instanceof INamingContainer);
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Returns a unique ID that identifies the control in the page hierarchy.
+ * A unique ID is the contenation of all naming container controls' IDs and the control ID.
+ * These IDs are separated by '$' character.
+ * Control users should not rely on the specific format of UniqueID, however.
+ * @return string a unique ID that identifies the control in the page hierarchy
+ */
+ public function getUniqueID()
+ {
+ if($this->_uid==='' || $this->_uid===null) // need to build the UniqueID
+ {
+ $this->_uid=''; // set to not-null, so that clearCachedUniqueID() may take action
+ if($namingContainer=$this->getNamingContainer())
+ {
+ if($this->getPage()===$namingContainer)
+ return ($this->_uid=$this->_id);
+ else if(($prefix=$namingContainer->getUniqueID())==='')
+ return $this->_id;
+ else
+ return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id);
+ }
+ else // no naming container
+ return $this->_id;
+ }
+ else
+ return $this->_uid;
+ }
+
+ /**
+ * Sets input focus to this control.
+ */
+ public function focus()
+ {
+ $this->getPage()->setFocus($this);
+ }
+
+ /**
+ * Returns the client ID of the control.
+ * The client ID can be used to uniquely identify
+ * the control in client-side scripts (such as JavaScript).
+ * Do not rely on the explicit format of the return ID.
+ * @return string the client ID of the control
+ */
+ public function getClientID()
+ {
+ return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * Converts a unique ID to a client ID.
+ * @param string the unique ID of a control
+ * @return string the client ID of the control
+ */
+ public static function convertUniqueIdToClientId($uniqueID)
+ {
+ return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR);
+ }
+
+ /**
+ * @return string the skin ID of this control, '' if not set
+ */
+ public function getSkinID()
+ {
+ return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:'';
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function setSkinID($value)
+ {
+ if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this));
+ else
+ $this->_rf[self::RF_SKIN_ID]=$value;
+ }
+
+ /**
+ * @param string the skin ID of this control
+ * @throws TInvalidOperationException if the SkinID is set in a stage later than PreInit, or if the skin is applied already.
+ */
+ public function getIsSkinApplied()
+ {
+ return ($this->_flags & self::IS_SKIN_APPLIED);
+ }
+
+ /**
+ * @return boolean whether theming is enabled for this control.
+ * The theming is enabled if the control and all its parents have it enabled.
+ */
+ public function getEnableTheming()
+ {
+ if($this->_flags & self::IS_DISABLE_THEMING)
+ return false;
+ else
+ return $this->_parent?$this->_parent->getEnableTheming():true;
+ }
+
+ /**
+ * @param boolean whether to enable theming
+ * @throws TInvalidOperationException if this method is invoked after OnPreInit
+ */
+ public function setEnableTheming($value)
+ {
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID());
+ else if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_THEMING;
+ else
+ $this->_flags |= self::IS_DISABLE_THEMING;
+ }
+
+ /**
+ * Returns custom data associated with this control.
+ * A control may be associated with some custom data for various purposes.
+ * For example, a button may be associated with a string to identify itself
+ * in a generic OnClick event handler.
+ * @return mixed custom data associated with this control. Defaults to null.
+ */
+ public function getCustomData()
+ {
+ return $this->getViewState('CustomData',null);
+ }
+
+ /**
+ * Associates custom data with this control.
+ * Note, the custom data must be serializable and unserializable.
+ * @param mixed custom data
+ */
+ public function setCustomData($value)
+ {
+ $this->setViewState('CustomData',$value,null);
+ }
+
+ /**
+ * @return boolean whether the control has child controls
+ */
+ public function getHasControls()
+ {
+ return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0;
+ }
+
+ /**
+ * @return TControlCollection the child control collection
+ */
+ public function getControls()
+ {
+ if(!isset($this->_rf[self::RF_CONTROLS]))
+ $this->_rf[self::RF_CONTROLS]=$this->createControlCollection();
+ return $this->_rf[self::RF_CONTROLS];
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TControlCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this);
+ }
+
+ /**
+ * Checks if a control is visible.
+ * If parent check is required, then a control is visible only if the control
+ * and all its ancestors are visible.
+ * @param boolean whether the parents should also be checked if visible
+ * @return boolean whether the control is visible (default=true).
+ */
+ public function getVisible($checkParents=true)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getVisible(false))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the control is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a value indicating whether the control is enabled.
+ * A control is enabled if it allows client user interaction.
+ * If $checkParents is true, all parent controls will be checked,
+ * and unless they are all enabled, false will be returned.
+ * The property Enabled is mainly used for {@link TWebControl}
+ * derived controls.
+ * @param boolean whether the parents should also be checked enabled
+ * @return boolean whether the control is enabled.
+ */
+ public function getEnabled($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control;$control=$control->_parent)
+ if(!$control->getViewState('Enabled',true))
+ return false;
+ return true;
+ }
+ else
+ return $this->getViewState('Enabled',true);
+ }
+
+ /**
+ * @param boolean whether the control is to be enabled.
+ */
+ public function setEnabled($value)
+ {
+ $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the control has custom attributes
+ */
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the list of custom attributes.
+ * Custom attributes are name-value pairs that may be rendered
+ * as HTML tags' attributes.
+ * @return TAttributeCollection the list of custom attributes
+ */
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * Sets a custom control attribute.
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, null if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether viewstate is enabled
+ */
+ public function getEnableViewState($checkParents=false)
+ {
+ if($checkParents)
+ {
+ for($control=$this;$control!==null;$control=$control->getParent())
+ if($control->_flags & self::IS_DISABLE_VIEWSTATE)
+ return false;
+ return true;
+ }
+ else
+ return !($this->_flags & self::IS_DISABLE_VIEWSTATE);
+ }
+
+ /**
+ * @param boolean set whether to enable viewstate
+ */
+ public function setEnableViewState($value)
+ {
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags &= ~self::IS_DISABLE_VIEWSTATE;
+ else
+ $this->_flags |= self::IS_DISABLE_VIEWSTATE;
+ }
+
+ /**
+ * Returns a controlstate value.
+ *
+ * This function is mainly used in defining getter functions for control properties
+ * that must be kept in controlstate.
+ * @param string the name of the controlstate value to be returned
+ * @param mixed the default value. If $key is not found in controlstate, $defaultValue will be returned
+ * @return mixed the controlstate value corresponding to $key
+ */
+ protected function getControlState($key,$defaultValue=null)
+ {
+ return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a controlstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in controlstate.
+ * Make sure that the controlstate value must be serializable and unserializable.
+ * @param string the name of the controlstate value
+ * @param mixed the controlstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from controlstate
+ */
+ protected function setControlState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ else
+ $this->_rf[self::RF_CONTROLSTATE][$key]=$value;
+ }
+
+ /**
+ * Clears a controlstate value.
+ * @param string the name of the controlstate value to be cleared
+ */
+ protected function clearControlState($key)
+ {
+ unset($this->_rf[self::RF_CONTROLSTATE][$key]);
+ }
+
+ /**
+ * Sets a value indicating whether we should keep data in viewstate.
+ * When it is false, data saved via setViewState() will not be persisted.
+ * By default, it is true, meaning data will be persisted across postbacks.
+ * @param boolean whether data should be persisted
+ */
+ public function trackViewState($enabled)
+ {
+ $this->_trackViewState=TPropertyValue::ensureBoolean($enabled);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * This function is very useful in defining getter functions for component properties
+ * that must be kept in viewstate.
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ public function getViewState($key,$defaultValue=null)
+ {
+ if(isset($this->_viewState[$key]))
+ return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue;
+ else if(isset($this->_tempState[$key]))
+ {
+ if(is_object($this->_tempState[$key]) && $this->_trackViewState)
+ $this->_viewState[$key]=$this->_tempState[$key];
+ return $this->_tempState[$key];
+ }
+ else
+ return $defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in viewstate.
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ public function setViewState($key,$value,$defaultValue=null)
+ {
+ if($this->_trackViewState)
+ {
+ $this->_viewState[$key]=$value;
+ unset($this->_tempState[$key]);
+ }
+ else
+ {
+ unset($this->_viewState[$key]);
+ $this->_tempState[$key]=$value;
+ }
+ }
+
+ /**
+ * Clears a viewstate value.
+ * @param string the name of the viewstate value to be cleared
+ */
+ public function clearViewState($key)
+ {
+ unset($this->_viewState[$key]);
+ unset($this->_tempState[$key]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function bindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Breaks the binding between a property (or property path) and an expression.
+ * @param string the property name (or property path)
+ */
+ public function unbindProperty($name)
+ {
+ unset($this->_rf[self::RF_DATA_BINDINGS][$name]);
+ }
+
+ /**
+ * Sets up the binding between a property (or property path) and an expression.
+ * Unlike regular databinding, the expression bound by this method
+ * is automatically evaluated during {@link prerenderRecursive()}.
+ * The context of the expression is the template control (or the control itself if it is a page).
+ * @param string the property name, or property path
+ * @param string the expression
+ */
+ public function autoBindProperty($name,$expression)
+ {
+ $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression;
+ }
+
+ /**
+ * Performs the databinding for this control.
+ */
+ public function dataBind()
+ {
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+ $this->dataBindChildren();
+ }
+
+ /**
+ * Databinding properties of the control.
+ */
+ protected function dataBindProperties()
+ {
+ Prado::trace("Data bind properties",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_DATA_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Auto databinding properties of the control.
+ */
+ protected function autoDataBindProperties()
+ {
+ if(isset($this->_rf[self::RF_AUTO_BINDINGS]))
+ {
+ if(($context=$this->getTemplateControl())===null)
+ $context=$this;
+ foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression)
+ $this->setSubProperty($property,$context->evaluateExpression($expression));
+ }
+ }
+
+ /**
+ * Databinding child controls.
+ */
+ protected function dataBindChildren()
+ {
+ Prado::trace("dataBindChildren()",'System.Web.UI.TControl');
+ if(isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof IBindable)
+ $control->dataBind();
+ }
+ }
+
+ /**
+ * @return boolean whether child controls have been created
+ */
+ final protected function getChildControlsCreated()
+ {
+ return ($this->_flags & self::IS_CHILD_CREATED)!==0;
+ }
+
+ /**
+ * Sets a value indicating whether child controls are created.
+ * If false, any existing child controls will be cleared up.
+ * @param boolean whether child controls are created
+ */
+ final protected function setChildControlsCreated($value)
+ {
+ if($value)
+ $this->_flags |= self::IS_CHILD_CREATED;
+ else
+ {
+ if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED))
+ $this->getControls()->clear();
+ $this->_flags &= ~self::IS_CHILD_CREATED;
+ }
+ }
+
+ /**
+ * Ensures child controls are created.
+ * If child controls are not created yet, this method will invoke
+ * {@link createChildControls} to create them.
+ */
+ public function ensureChildControls()
+ {
+ if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD))
+ {
+ try
+ {
+ $this->_flags |= self::IS_CREATING_CHILD;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->createChildControls();
+ else
+ $this->createChildControls();
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ }
+ catch(Exception $e)
+ {
+ $this->_flags &= ~self::IS_CREATING_CHILD;
+ $this->_flags |= self::IS_CHILD_CREATED;
+ throw $e;
+ }
+ }
+ }
+
+ /**
+ * Creates child controls.
+ * This method can be overriden for controls who want to have their controls.
+ * Do not call this method directly. Instead, call {@link ensureChildControls}
+ * to ensure child controls are created only once.
+ */
+ public function createChildControls()
+ {
+ }
+
+ /**
+ * Finds a control by ID path within the current naming container.
+ * The current naming container is either the control itself
+ * if it implements {@link INamingContainer} or the control's naming container.
+ * The ID path is an ID sequence separated by {@link TControl::ID_SEPARATOR}.
+ * For example, 'Repeater1.Item1.Button1' looks for a control with ID 'Button1'
+ * whose naming container is 'Item1' whose naming container is 'Repeater1'.
+ * @param string ID of the control to be looked up
+ * @return TControl|null the control found, null if not found
+ * @throws TInvalidDataValueException if a control's ID is found not unique within its naming container.
+ */
+ public function findControl($id)
+ {
+ $id=strtr($id,'.',self::ID_SEPARATOR);
+ $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer();
+ if(!$container || !$container->getHasControls())
+ return null;
+ if(!isset($container->_rf[self::RF_NAMED_CONTROLS]))
+ {
+ $container->_rf[self::RF_NAMED_CONTROLS]=array();
+ $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]);
+ }
+ if(($pos=strpos($id,self::ID_SEPARATOR))===false)
+ return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null;
+ else
+ {
+ $cid=substr($id,0,$pos);
+ $sid=substr($id,$pos+1);
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid]))
+ return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid);
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Finds all child and grand-child controls that are of the specified type.
+ * @param string the class name
+ * @param boolean whether the type comparison is strict or not. If false, controls of the parent classes of the specified class will also be returned.
+ * @return array list of controls found
+ */
+ public function findControlsByType($type,$strict=true)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type))))
+ $controls[]=$control;
+ if(($control instanceof TControl) && $control->getHasControls())
+ $controls=array_merge($controls,$control->findControlsByType($type,$strict));
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Finds all child and grand-child controls with the specified ID.
+ * Note, this method is different from {@link findControl} in that
+ * it searches through all controls that have this control as the ancestor
+ * while {@link findcontrol} only searches through controls that have this
+ * control as the direct naming container.
+ * @param string the ID being looked for
+ * @return array list of controls found
+ */
+ public function findControlsByID($id)
+ {
+ $controls=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id===$id)
+ $controls[]=$control;
+ $controls=array_merge($controls,$control->findControlsByID($id));
+ }
+ }
+ }
+ return $controls;
+ }
+
+ /**
+ * Resets the control as a naming container.
+ * Only framework developers should use this method.
+ */
+ public function clearNamingContainer()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS_ID]);
+ $this->clearNameTable();
+ }
+
+ /**
+ * Registers an object by a name.
+ * A registered object can be accessed like a public member variable.
+ * This method should only be used by framework and control developers.
+ * @param string name of the object
+ * @param object object to be declared
+ * @see __get
+ */
+ public function registerObject($name,$object)
+ {
+ if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name]))
+ throw new TInvalidOperationException('control_object_reregistered',$name);
+ $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object;
+ }
+
+ /**
+ * Unregisters an object by name.
+ * @param string name of the object
+ * @see registerObject
+ */
+ public function unregisterObject($name)
+ {
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean whether an object has been registered with the name
+ * @see registerObject
+ */
+ public function isObjectRegistered($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]);
+ }
+
+ /**
+ * @return boolean true if the child control has been initialized.
+ */
+ public function getHasChildInitialized()
+ {
+ return $this->getControlStage() >= self::CS_CHILD_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the onInit event has raised.
+ */
+ public function getHasInitialized()
+ {
+ return $this->getControlStage() >= self::CS_INITIALIZED;
+ }
+
+ /**
+ * @return boolean true if the control has loaded post data.
+ */
+ public function getHasLoadedPostData()
+ {
+ return $this->getControlStage() >= self::CS_STATE_LOADED;
+ }
+
+ /**
+ * @return boolean true if the onLoad event has raised.
+ */
+ public function getHasLoaded()
+ {
+ return $this->getControlStage() >= self::CS_LOADED;
+ }
+
+ /**
+ * @return boolean true if onPreRender event has raised.
+ */
+ public function getHasPreRendered()
+ {
+ return $this->getControlStage() >= self::CS_PRERENDERED;
+ }
+
+ /**
+ * Returns the named registered object.
+ * A component with explicit ID on a template will be registered to
+ * the template owner. This method allows you to obtain this component
+ * with the ID.
+ * @return mixed the named registered object. Null if object is not found.
+ */
+ public function getRegisteredObject($name)
+ {
+ return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null;
+ }
+
+ /**
+ * @return boolean whether body contents are allowed for this control. Defaults to true.
+ */
+ public function getAllowChildControls()
+ {
+ return true;
+ }
+
+ /**
+ * Adds the object instantiated on a template to the child control collection.
+ * This method overrides the parent implementation.
+ * Only framework developers and control developers should use this method.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Clears up the child state data.
+ * After a control loads its state, those state that do not belong to
+ * any existing child controls are stored as child state.
+ * This method will remove these state.
+ * Only frameworker developers and control developers should use this method.
+ */
+ final protected function clearChildState()
+ {
+ unset($this->_rf[self::RF_CHILD_STATE]);
+ }
+
+ /**
+ * @param TControl the potential ancestor control
+ * @return boolean if the control is a descendent (parent, parent of parent, etc.)
+ * of the specified control
+ */
+ final protected function isDescendentOf($ancestor)
+ {
+ $control=$this;
+ while($control!==$ancestor && $control->_parent)
+ $control=$control->_parent;
+ return $control===$ancestor;
+ }
+
+ /**
+ * Adds a control into the child collection of the control.
+ * Control lifecycles will be caught up during the addition.
+ * Only framework developers should use this method.
+ * @param TControl the new child control
+ */
+ public function addedControl($control)
+ {
+ if($control->_parent)
+ $control->_parent->getControls()->remove($control);
+ $control->_parent=$this;
+ $control->_page=$this->getPage();
+ $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer;
+ if($namingContainer)
+ {
+ $control->_namingContainer=$namingContainer;
+ if($control->_id==='')
+ $control->generateAutomaticID();
+ else
+ $namingContainer->clearNameTable();
+ $control->clearCachedUniqueID($control instanceof INamingContainer);
+ }
+
+ if($this->_stage>=self::CS_CHILD_INITIALIZED)
+ {
+ $control->initRecursive($namingContainer);
+ if($this->_stage>=self::CS_STATE_LOADED)
+ {
+ if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id]))
+ {
+ $state=$this->_rf[self::RF_CHILD_STATE][$control->_id];
+ unset($this->_rf[self::RF_CHILD_STATE][$control->_id]);
+ }
+ else
+ $state=null;
+ $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if($this->_stage>=self::CS_LOADED)
+ {
+ $control->loadRecursive();
+ if($this->_stage>=self::CS_PRERENDERED)
+ $control->preRenderRecursive();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a control from the child collection of the control.
+ * Only framework developers should use this method.
+ * @param TControl the child control removed
+ */
+ public function removedControl($control)
+ {
+ if($this->_namingContainer)
+ $this->_namingContainer->clearNameTable();
+ $control->unloadRecursive();
+ $control->_parent=null;
+ $control->_page=null;
+ $control->_namingContainer=null;
+ $control->_tplControl=null;
+ //$control->_stage=self::CS_CONSTRUCTED;
+ if(!($control->_flags & self::IS_ID_SET))
+ $control->_id='';
+ else
+ unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]);
+ $control->clearCachedUniqueID(true);
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this instanceof INamingContainer)
+ $namingContainer=$this;
+ $page=$this->getPage();
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->_namingContainer=$namingContainer;
+ $control->_page=$page;
+ if($control->_id==='' && $namingContainer)
+ $control->generateAutomaticID();
+ $control->initRecursive($namingContainer);
+ }
+ }
+ }
+ if($this->_stage<self::CS_INITIALIZED)
+ {
+ $this->_stage=self::CS_CHILD_INITIALIZED;
+ if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED))
+ {
+ $page->applyControlSkin($this);
+ $this->_flags |= self::IS_SKIN_APPLIED;
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onInit(null);
+ else
+ $this->onInit(null);
+ $this->_stage=self::CS_INITIALIZED;
+ }
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function loadRecursive()
+ {
+ if($this->_stage<self::CS_LOADED)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onLoad(null);
+ else
+ $this->onLoad(null);
+ }
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->loadRecursive();
+ }
+ }
+ if($this->_stage<self::CS_LOADED)
+ $this->_stage=self::CS_LOADED;
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function preRenderRecursive()
+ {
+ $this->autoDataBindProperties();
+
+ if($this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onPreRender(null);
+ else
+ $this->onPreRender(null);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->preRenderRecursive();
+ else if($control instanceof TCompositeLiteral)
+ $control->evaluateDynamicContent();
+ }
+ }
+ $this->addToPostDataLoader();
+ }
+ $this->_stage=self::CS_PRERENDERED;
+ }
+
+ /**
+ * Add controls implementing IPostBackDataHandler to post data loaders.
+ */
+ protected function addToPostDataLoader()
+ {
+ if($this instanceof IPostBackDataHandler)
+ $this->getPage()->registerPostDataLoader($this);
+ }
+
+ /**
+ * Performs the Unload step for the control and all its child controls.
+ * Only framework developers should use this method.
+ */
+ protected function unloadRecursive()
+ {
+ if(!($this->_flags & self::IS_ID_SET))
+ $this->_id='';
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->unloadRecursive();
+ }
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->onUnload(null);
+ else
+ $this->onUnload(null);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * The method raises 'OnInit' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->raiseEvent('OnInit',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * The method raises 'OnLoad' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->raiseEvent('OnLoad',$this,$param);
+ }
+
+ /**
+ * Raises 'OnDataBinding' event.
+ * This method is invoked when {@link dataBind} is invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onDataBinding($param)
+ {
+ Prado::trace("onDataBinding()",'System.Web.UI.TControl');
+ $this->raiseEvent('OnDataBinding',$this,$param);
+ }
+
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * The method raises 'OnUnload' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->raiseEvent('OnUnload',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * The method raises 'OnPreRender' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->raiseEvent('OnPreRender',$this,$param);
+ }
+
+ /**
+ * Invokes the parent's bubbleEvent method.
+ * A control who wants to bubble an event must call this method in its onEvent method.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameter
+ * @see bubbleEvent
+ */
+ protected function raiseBubbleEvent($sender,$param)
+ {
+ $control=$this;
+ while($control=$control->_parent)
+ {
+ if($control->bubbleEvent($sender,$param))
+ break;
+ }
+ }
+
+ /**
+ * This method responds to a bubbled event.
+ * This method should be overriden to provide customized response to a bubbled event.
+ * Check the type of event parameter to determine what event is bubbled currently.
+ * @param TControl sender of the event
+ * @param TEventParameter event parameters
+ * @return boolean true if the event bubbling is handled and no more bubbling.
+ * @see raiseBubbleEvent
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ return false;
+ }
+
+ /**
+ * Broadcasts an event.
+ * The event will be sent to all controls on the current page hierarchy.
+ * If a control defines the event, the event will be raised for the control.
+ * If a control implements {@link IBroadcastEventReceiver}, its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()} method will
+ * be invoked which gives the control a chance to respond to the event.
+ * For example, when broadcasting event 'OnClick', all controls having 'OnClick'
+ * event will have this event raised, and all controls implementing
+ * {@link IBroadcastEventReceiver} will also have its
+ * {@link IBroadcastEventReceiver::broadcastEventReceived broadcastEventReceived()}
+ * invoked.
+ * @param string name of the broadcast event
+ * @param TControl sender of this event
+ * @param TEventParameter event parameter
+ */
+ public function broadcastEvent($name,$sender,$param)
+ {
+ $rootControl=(($page=$this->getPage())===null)?$this:$page;
+ $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param));
+ }
+
+ /**
+ * Recursively broadcasts an event.
+ * This method should only be used by framework developers.
+ * @param string name of the broadcast event
+ * @param TControl sender of the event
+ * @param TBroadcastEventParameter event parameter
+ */
+ private function broadcastEventInternal($name,$sender,$param)
+ {
+ if($this->hasEvent($name))
+ $this->raiseEvent($name,$sender,$param->getParameter());
+ if($this instanceof IBroadcastEventReceiver)
+ $this->broadcastEventReceived($sender,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $control->broadcastEventInternal($name,$sender,$param);
+ }
+ }
+ }
+
+ /**
+ * Traverse the whole control hierarchy rooted at this control.
+ * Callback function may be invoked for each control being visited.
+ * A pre-callback is invoked before traversing child controls;
+ * A post-callback is invoked after traversing child controls.
+ * Callback functions can be global functions or class methods.
+ * They must be of the following signature:
+ * <code>
+ * function callback_func($control,$param) {...}
+ * </code>
+ * where $control refers to the control being visited and $param
+ * is the parameter that is passed originally when calling this traverse function.
+ *
+ * @param mixed parameter to be passed to callbacks for each control
+ * @param callback callback invoked before traversing child controls. If null, it is ignored.
+ * @param callback callback invoked after traversing child controls. If null, it is ignored.
+ */
+ protected function traverseChildControls($param,$preCallback=null,$postCallback=null)
+ {
+ if($preCallback!==null)
+ call_user_func($preCallback,$this,$param);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ $control->traverseChildControls($param,$preCallback,$postCallback);
+ }
+ }
+ }
+ if($postCallback!==null)
+ call_user_func($postCallback,$this,$param);
+ }
+
+ /**
+ * Renders the control.
+ * Only when the control is visible will the control be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderControl($writer)
+ {
+ if($this instanceof IActiveControl || $this->getVisible(false))
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->render($writer);
+ else
+ $this->render($writer);
+ }
+ }
+
+ /**
+ * Renders the control.
+ * This method is invoked by {@link renderControl} when the control is visible.
+ * You can override this method to provide customized rendering of the control.
+ * By default, the control simply renders all its child contents.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderChildren($writer);
+ }
+
+ /**
+ * Renders the children of the control.
+ * This method iterates through all child controls and static text strings
+ * and renders them in order.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if(is_string($control))
+ $writer->write($control);
+ else if($control instanceof TControl)
+ $control->renderControl($writer);
+ else if($control instanceof IRenderable)
+ $control->render($writer);
+ }
+ }
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ if(is_array($state))
+ {
+ // A null state means the stateful properties all take default values.
+ // So if the state is enabled, we have to assign the null value.
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ if(isset($state[1]))
+ {
+ $this->_rf[self::RF_CONTROLSTATE]=&$state[1];
+ unset($state[1]);
+ }
+ else
+ unset($this->_rf[self::RF_CONTROLSTATE]);
+ if($needViewState)
+ {
+ if(isset($state[0]))
+ $this->_viewState=&$state[0];
+ else
+ $this->_viewState=array();
+ }
+ unset($state[0]);
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if(isset($state[$control->_id]))
+ {
+ $control->loadStateRecursive($state[$control->_id],$needViewState);
+ unset($state[$control->_id]);
+ }
+ }
+ }
+ }
+ if(!empty($state))
+ $this->_rf[self::RF_CHILD_STATE]=&$state;
+ }
+ $this->_stage=self::CS_STATE_LOADED;
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->loadState();
+ else
+ $this->loadState();
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if(isset($this->_rf[self::RF_ADAPTER]))
+ $this->_rf[self::RF_ADAPTER]->saveState();
+ else
+ $this->saveState();
+ $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE));
+ $state=array();
+ if($this->getHasControls())
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ {
+ if($control instanceof TControl)
+ $state[$control->_id]=&$control->saveStateRecursive($needViewState);
+ }
+ }
+ if($needViewState && !empty($this->_viewState))
+ $state[0]=&$this->_viewState;
+ if(isset($this->_rf[self::RF_CONTROLSTATE]))
+ $state[1]=&$this->_rf[self::RF_CONTROLSTATE];
+ return $state;
+ }
+
+ /**
+ * Applies a stylesheet skin to a control.
+ * @param TPage the page containing the control
+ * @throws TInvalidOperationException if the stylesheet skin is applied already
+ */
+ public function applyStyleSheetSkin($page)
+ {
+ if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED))
+ {
+ $page->applyControlStyleSheet($this);
+ $this->_flags |= self::IS_STYLESHEET_APPLIED;
+ }
+ else if($this->_flags & self::IS_STYLESHEET_APPLIED)
+ throw new TInvalidOperationException('control_stylesheet_applied',get_class($this));
+ }
+
+ /**
+ * Clears the cached UniqueID.
+ * If $recursive=true, all children's cached UniqueID will be cleared as well.
+ * @param boolean whether the clearing is recursive.
+ */
+ private function clearCachedUniqueID($recursive)
+ {
+ if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS]))
+ {
+ foreach($this->_rf[self::RF_CONTROLS] as $control)
+ if($control instanceof TControl)
+ $control->clearCachedUniqueID($recursive);
+ }
+ $this->_uid=null;
+ }
+
+ /**
+ * Generates an automatic ID for the control.
+ */
+ private function generateAutomaticID()
+ {
+ $this->_flags &= ~self::IS_ID_SET;
+ if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]))
+ $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0;
+ $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++;
+ $this->_id=self::AUTOMATIC_ID_PREFIX . $id;
+ $this->_namingContainer->clearNameTable();
+ }
+
+ /**
+ * Clears the list of the controls whose IDs are managed by the specified naming container.
+ */
+ private function clearNameTable()
+ {
+ unset($this->_rf[self::RF_NAMED_CONTROLS]);
+ }
+
+ /**
+ * Updates the list of the controls whose IDs are managed by the specified naming container.
+ * @param TControl the naming container
+ * @param TControlCollection list of controls
+ * @throws TInvalidDataValueException if a control's ID is not unique within its naming container.
+ */
+ private function fillNameTable($container,$controls)
+ {
+ foreach($controls as $control)
+ {
+ if($control instanceof TControl)
+ {
+ if($control->_id!=='')
+ {
+ if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id]))
+ throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id);
+ else
+ $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control;
+ }
+ if(!($control instanceof INamingContainer) && $control->getHasControls())
+ $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]);
+ }
+ }
+ }
+}
+
+
+/**
+ * TControlCollection class
+ *
+ * TControlCollection implements a collection that enables
+ * controls to maintain a list of their child controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ * @param boolean whether the list is read-only
+ */
+ public function __construct(TControl $owner,$readOnly=false)
+ {
+ $this->_o=$owner;
+ parent::__construct(null,$readOnly);
+ }
+
+ /**
+ * @return TControl the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added child control.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ {
+ parent::insertAt($index,$item);
+ $this->_o->addedControl($item);
+ }
+ else if(is_string($item) || ($item instanceof IRenderable))
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('controlcollection_control_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * cleanup work when removing a child control.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $item=parent::removeAt($index);
+ if($item instanceof TControl)
+ $this->_o->removedControl($item);
+ return $item;
+ }
+
+ /**
+ * Overrides the parent implementation by invoking {@link TControl::clearNamingContainer}
+ */
+ public function clear()
+ {
+ parent::clear();
+ if($this->_o instanceof INamingContainer)
+ $this->_o->clearNamingContainer();
+ }
+}
+
+/**
+ * TEmptyControlCollection class
+ *
+ * TEmptyControlCollection implements an empty control list that prohibits adding
+ * controls to it. This is useful for controls that do not allow child controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TEmptyControlCollection extends TControlCollection
+{
+ /**
+ * Constructor.
+ * @param TControl the control that owns this collection.
+ */
+ public function __construct(TControl $owner)
+ {
+ parent::__construct($owner,true);
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by ignoring new addition.
+ * @param integer the speicified position.
+ * @param mixed new item
+ */
+ public function insertAt($index,$item)
+ {
+ if(!is_string($item)) // string is possible if property tag is used. we simply ignore it in this case
+ parent::insertAt($index,$item); // this will generate an exception in parent implementation
+ }
+}
+
+/**
+ * INamingContainer interface.
+ * INamingContainer marks a control as a naming container.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface INamingContainer
+{
+}
+
+/**
+ * IPostBackEventHandler interface
+ *
+ * If a control wants to respond to postback event, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackEventHandler
+{
+ /**
+ * Raises postback event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnClick, OnCommand)
+ * indicating the component is responsible for the postback event.
+ * @param string the parameter associated with the postback event
+ */
+ public function raisePostBackEvent($param);
+}
+
+/**
+ * IPostBackDataHandler interface
+ *
+ * If a control wants to load post data, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IPostBackDataHandler
+{
+ /**
+ * Loads user input data.
+ * The implementation of this function can use $values[$key] to get the user input
+ * data that are meant for the particular control.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values);
+ /**
+ * Raises postdata changed event.
+ * The implementation of this function should raise appropriate event(s) (e.g. OnTextChanged)
+ * indicating the control data is changed.
+ */
+ public function raisePostDataChangedEvent();
+ /**
+ * @return boolean whether postback causes the data change. Defaults to false for non-postback state.
+ */
+ public function getDataChanged();
+}
+
+
+/**
+ * IValidator interface
+ *
+ * If a control wants to validate user input, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidator
+{
+ /**
+ * Validates certain data.
+ * The implementation of this function should validate certain data
+ * (e.g. data entered into TTextBox control).
+ * @return boolean whether the data passes the validation
+ */
+ public function validate();
+ /**
+ * @return boolean whether the previous {@link validate()} is successful.
+ */
+ public function getIsValid();
+ /**
+ * @param boolean whether the validator validates successfully
+ */
+ public function setIsValid($value);
+ /**
+ * @return string error message during last validate
+ */
+ public function getErrorMessage();
+ /**
+ * @param string error message for the validation
+ */
+ public function setErrorMessage($value);
+}
+
+
+/**
+ * IValidatable interface
+ *
+ * If a control wants to be validated by a validator, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IValidatable
+{
+ /**
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue();
+ /**
+ * @return boolean wether this control's validators validated successfully (must default to true)
+ */
+ public function getIsValid();
+ /**
+ * @return boolean wether this control's validators validated successfully
+ */
+ public function setIsValid($value);
+}
+
+/**
+ * IBroadcastEventReceiver interface
+ *
+ * If a control wants to check broadcast event, it must implement this interface.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IBroadcastEventReceiver
+{
+ /**
+ * Handles broadcast event.
+ * This method is invoked automatically when an event is broadcasted.
+ * Within this method, you may check the event name given in
+ * the event parameter to determine whether you should respond to
+ * this event.
+ * @param TControl sender of the event
+ * @param TBroadCastEventParameter event parameter
+ */
+ public function broadcastEventReceived($sender,$param);
+}
+
+/**
+ * ITheme interface.
+ *
+ * This interface must be implemented by theme.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITheme
+{
+ /**
+ * Applies this theme to the specified control.
+ * @param TControl the control to be applied with this theme
+ */
+ public function applySkin($control);
+}
+
+/**
+ * ITemplate interface
+ *
+ * ITemplate specifies the interface for classes encapsulating
+ * parsed template structures.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface ITemplate
+{
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the parent control
+ */
+ public function instantiateIn($parent);
+}
+
+/**
+ * IButtonControl interface
+ *
+ * IButtonControl specifies the common properties and events that must
+ * be implemented by a button control, such as {@link TButton}, {@link TLinkButton},
+ * {@link TImageButton}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+interface IButtonControl
+{
+ /**
+ * @return string caption of the button
+ */
+ public function getText();
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value);
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation
+ */
+ public function getCausesValidation();
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value);
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName();
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value);
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter();
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value);
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup();
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value);
+
+ /**
+ * Raises <b>OnClick</b> event.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param);
+
+ /**
+ * Raises <b>OnCommand</b> event.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param);
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value);
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton();
+}
+
+/**
+ * ISurroundable interface
+ *
+ * Identifies controls that may create an additional surrounding tag. The id of the
+ * tag can be obtained with {@link getSurroundingTagID}.
+ *
+ * @package System.Web.UI
+ * @since 3.1.2
+ */
+interface ISurroundable
+{
+ /**
+ * @return string the id of the embedding tag of the control or the control's clientID if not surrounded
+ */
+ public function getSurroundingTagID();
+}
+
+/**
+ * TBroadcastEventParameter class
+ *
+ * TBroadcastEventParameter encapsulates the parameter data for
+ * events that are broadcasted. The name of of the event is specified via
+ * {@link setName Name} property while the event parameter is via
+ * {@link setParameter Parameter} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TBroadcastEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the broadcast event
+ * @param mixed parameter of the broadcast event
+ */
+ public function __construct($name='',$parameter=null)
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the broadcast event
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name of the broadcast event
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return mixed parameter of the broadcast event
+ */
+ public function getParameter()
+ {
+ return $this->_param;
+ }
+
+ /**
+ * @param mixed parameter of the broadcast event
+ */
+ public function setParameter($value)
+ {
+ $this->_param=$value;
+ }
+}
+
+/**
+ * TCommandEventParameter class
+ *
+ * TCommandEventParameter encapsulates the parameter data for <b>Command</b>
+ * event of button controls. You can access the name of the command via
+ * {@link getCommandName CommandName} property, and the parameter carried
+ * with the command via {@link getCommandParameter CommandParameter} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCommandEventParameter extends TEventParameter
+{
+ private $_name;
+ private $_param;
+
+ /**
+ * Constructor.
+ * @param string name of the command
+ * @param string parameter of the command
+ */
+ public function __construct($name='',$parameter='')
+ {
+ $this->_name=$name;
+ $this->_param=$parameter;
+ }
+
+ /**
+ * @return string name of the command
+ */
+ public function getCommandName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @return string parameter of the command
+ */
+ public function getCommandParameter()
+ {
+ return $this->_param;
+ }
+}
+
+
+/**
+ * TCompositeLiteral class
+ *
+ * TCompositeLiteral is used internally by {@link TTemplate} for representing
+ * consecutive static strings, expressions and statements.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TCompositeLiteral extends TComponent implements IRenderable, IBindable
+{
+ const TYPE_EXPRESSION=0;
+ const TYPE_STATEMENTS=1;
+ const TYPE_DATABINDING=2;
+ private $_container=null;
+ private $_items=array();
+ private $_expressions=array();
+ private $_statements=array();
+ private $_bindings=array();
+
+ /**
+ * Constructor.
+ * @param array list of items to be represented by TCompositeLiteral
+ */
+ public function __construct($items)
+ {
+ $this->_items=array();
+ $this->_expressions=array();
+ $this->_statements=array();
+ foreach($items as $id=>$item)
+ {
+ if(is_array($item))
+ {
+ if($item[0]===self::TYPE_EXPRESSION)
+ $this->_expressions[$id]=$item[1];
+ else if($item[0]===self::TYPE_STATEMENTS)
+ $this->_statements[$id]=$item[1];
+ else if($item[0]===self::TYPE_DATABINDING)
+ $this->_bindings[$id]=$item[1];
+ $this->_items[$id]='';
+ }
+ else
+ $this->_items[$id]=$item;
+ }
+ }
+
+ /**
+ * @return TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function getContainer()
+ {
+ return $this->_container;
+ }
+
+ /**
+ * @param TComponent container of this component. It serves as the evaluation context of expressions and statements.
+ */
+ public function setContainer(TComponent $value)
+ {
+ $this->_container=$value;
+ }
+
+ /**
+ * Evaluates the expressions and/or statements in the component.
+ */
+ public function evaluateDynamicContent()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_expressions as $id=>$expression)
+ $this->_items[$id]=$context->evaluateExpression($expression);
+ foreach($this->_statements as $id=>$statement)
+ $this->_items[$id]=$context->evaluateStatements($statement);
+ }
+
+ /**
+ * Performs databindings.
+ * This method is required by {@link IBindable}
+ */
+ public function dataBind()
+ {
+ $context=$this->_container===null?$this:$this->_container;
+ foreach($this->_bindings as $id=>$binding)
+ $this->_items[$id]=$context->evaluateExpression($binding);
+ }
+
+ /**
+ * Renders the content stored in this component.
+ * This method is required by {@link IRenderable}
+ * @param ITextWriter
+ */
+ public function render($writer)
+ {
+ $writer->write(implode('',$this->_items));
+ }
+}
+
+?>
diff --git a/framework/Web/UI/TControlAdapter.php b/framework/Web/UI/TControlAdapter.php
index 5f06c360..a1afd353 100644
--- a/framework/Web/UI/TControlAdapter.php
+++ b/framework/Web/UI/TControlAdapter.php
@@ -1,143 +1,143 @@
-<?php
-/**
- * TControlAdapter class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TControlAdapter class
- *
- * TControlAdapter is the base class for adapters that customize
- * various behaviors for the control to which the adapter is attached.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TControlAdapter extends TApplicationComponent
-{
- /**
- * @var TControl the control to which the adapter is attached
- */
- protected $_control;
-
- /**
- * Constructor.
- * @param TControl the control to which the adapter is attached
- */
- public function __construct($control)
- {
- $this->_control=$control;
- }
-
- /**
- * @return TControl the control to which this adapter is attached
- */
- public function getControl()
- {
- return $this->_control;
- }
-
- /**
- * @return TPage the page that contains the attached control
- */
- public function getPage()
- {
- return $this->_control?$this->_control->getPage():null;
- }
-
- /**
- * Creates child controls for the attached control.
- * Default implementation calls the attached control's corresponding method.
- */
- public function createChildControls()
- {
- $this->_control->createChildControls();
- }
-
- /**
- * Loads additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function loadState()
- {
- $this->_control->loadState();
- }
-
- /**
- * Saves additional persistent control state.
- * Default implementation calls the attached control's corresponding method.
- */
- public function saveState()
- {
- $this->_control->saveState();
- }
-
- /**
- * This method is invoked when the control enters 'OnInit' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- $this->_control->onInit($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnLoad' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onLoad($param)
- {
- $this->_control->onLoad($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnPreRender' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onPreRender($param)
- {
- $this->_control->onPreRender($param);
- }
-
- /**
- * This method is invoked when the control enters 'OnUnload' stage.
- * Default implementation calls the attached control's corresponding method.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnload($param)
- {
- $this->_control->onUnload($param);
- }
-
- /**
- * This method is invoked when the control renders itself.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- $this->_control->render($writer);
- }
-
- /**
- * Renders the control's children.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderChildren($writer)
- {
- $this->_control->renderChildren($writer);
- }
-}
-
+<?php
+/**
+ * TControlAdapter class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TControlAdapter class
+ *
+ * TControlAdapter is the base class for adapters that customize
+ * various behaviors for the control to which the adapter is attached.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TControlAdapter extends TApplicationComponent
+{
+ /**
+ * @var TControl the control to which the adapter is attached
+ */
+ protected $_control;
+
+ /**
+ * Constructor.
+ * @param TControl the control to which the adapter is attached
+ */
+ public function __construct($control)
+ {
+ $this->_control=$control;
+ }
+
+ /**
+ * @return TControl the control to which this adapter is attached
+ */
+ public function getControl()
+ {
+ return $this->_control;
+ }
+
+ /**
+ * @return TPage the page that contains the attached control
+ */
+ public function getPage()
+ {
+ return $this->_control?$this->_control->getPage():null;
+ }
+
+ /**
+ * Creates child controls for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function createChildControls()
+ {
+ $this->_control->createChildControls();
+ }
+
+ /**
+ * Loads additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function loadState()
+ {
+ $this->_control->loadState();
+ }
+
+ /**
+ * Saves additional persistent control state.
+ * Default implementation calls the attached control's corresponding method.
+ */
+ public function saveState()
+ {
+ $this->_control->saveState();
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnInit' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ $this->_control->onInit($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnLoad' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onLoad($param)
+ {
+ $this->_control->onLoad($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnPreRender' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onPreRender($param)
+ {
+ $this->_control->onPreRender($param);
+ }
+
+ /**
+ * This method is invoked when the control enters 'OnUnload' stage.
+ * Default implementation calls the attached control's corresponding method.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnload($param)
+ {
+ $this->_control->onUnload($param);
+ }
+
+ /**
+ * This method is invoked when the control renders itself.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->_control->render($writer);
+ }
+
+ /**
+ * Renders the control's children.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderChildren($writer)
+ {
+ $this->_control->renderChildren($writer);
+ }
+}
+
diff --git a/framework/Web/UI/TForm.php b/framework/Web/UI/TForm.php
index f57f7482..2d60a4e4 100644
--- a/framework/Web/UI/TForm.php
+++ b/framework/Web/UI/TForm.php
@@ -1,171 +1,171 @@
-<?php
-/**
- * TForm class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TForm class
- *
- * TForm displays an HTML form. Besides regular body content,
- * it displays hidden fields, javascript blocks and files that are registered
- * through {@link TClientScriptManager}.
- *
- * A TForm is required for a page that needs postback.
- * Each page can contain at most one TForm. If multiple HTML forms are needed,
- * please use regular HTML form tags for those forms that post to different
- * URLs.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TForm extends TControl
-{
- /**
- * Registers the form with the page.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setForm($this);
- }
-
- /**
- * Adds form specific attributes to renderer.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $writer->addAttribute('method',$this->getMethod());
- $uri=$this->getRequest()->getRequestURI();
- $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
- if(($enctype=$this->getEnctype())!=='')
- $writer->addAttribute('enctype',$enctype);
-
- $attributes=$this->getAttributes();
- $attributes->remove('action');
- $writer->addAttributes($attributes);
-
- if(($butt=$this->getDefaultButton())!=='')
- {
- if(($button=$this->findControl($butt))!==null)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- else
- throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
- }
- }
-
- /**
- * Renders the form.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- $page=$this->getPage();
-
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag('form');
-
- $cs=$page->getClientScript();
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHiddenFieldsBegin($writer);
- $cs->renderScriptFilesBegin($writer);
- $cs->renderBeginScripts($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $cs->renderHiddenFieldsEnd($writer);
- $page->endFormRender($writer);
-
- $cs->renderScriptFilesEnd($writer);
- $cs->renderEndScripts($writer);
- }
- else
- {
- $cs->renderHiddenFieldsBegin($writer);
-
- $page->beginFormRender($writer);
- $this->renderChildren($writer);
- $page->endFormRender($writer);
-
- $cs->renderHiddenFieldsEnd($writer);
- }
-
- $writer->renderEndTag();
- }
-
- /**
- * @return string id path to the default button control.
- */
- public function getDefaultButton()
- {
- return $this->getViewState('DefaultButton','');
- }
-
- /**
- * Sets a button to be default one in a form.
- * A default button will be clicked if a user presses 'Enter' key within
- * the form.
- * @param string id path to the default button control.
- */
- public function setDefaultButton($value)
- {
- $this->setViewState('DefaultButton',$value,'');
- }
-
- /**
- * @return string form submission method. Defaults to 'post'.
- */
- public function getMethod()
- {
- return $this->getViewState('Method','post');
- }
-
- /**
- * @param string form submission method. Valid values include 'post' and 'get'.
- */
- public function setMethod($value)
- {
- $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
- }
-
- /**
- * @return string the encoding type a browser uses to post data back to the server
- */
- public function getEnctype()
- {
- return $this->getViewState('Enctype','');
- }
-
- /**
- * @param string the encoding type a browser uses to post data back to the server.
- * Commonly used types include
- * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
- * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
- * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
- */
- public function setEnctype($value)
- {
- $this->setViewState('Enctype',$value,'');
- }
-
- /**
- * @return string form name, which is equal to {@link getUniqueID UniqueID}.
- */
- public function getName()
- {
- return $this->getUniqueID();
- }
-}
-
+<?php
+/**
+ * TForm class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TForm class
+ *
+ * TForm displays an HTML form. Besides regular body content,
+ * it displays hidden fields, javascript blocks and files that are registered
+ * through {@link TClientScriptManager}.
+ *
+ * A TForm is required for a page that needs postback.
+ * Each page can contain at most one TForm. If multiple HTML forms are needed,
+ * please use regular HTML form tags for those forms that post to different
+ * URLs.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TForm extends TControl
+{
+ /**
+ * Registers the form with the page.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setForm($this);
+ }
+
+ /**
+ * Adds form specific attributes to renderer.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $writer->addAttribute('method',$this->getMethod());
+ $uri=$this->getRequest()->getRequestURI();
+ $writer->addAttribute('action',str_replace('&','&amp;',str_replace('&amp;','&',$uri)));
+ if(($enctype=$this->getEnctype())!=='')
+ $writer->addAttribute('enctype',$enctype);
+
+ $attributes=$this->getAttributes();
+ $attributes->remove('action');
+ $writer->addAttributes($attributes);
+
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ if(($button=$this->findControl($butt))!==null)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ else
+ throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt);
+ }
+ }
+
+ /**
+ * Renders the form.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag('form');
+
+ $cs=$page->getClientScript();
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+ $cs->renderScriptFilesBegin($writer);
+ $cs->renderBeginScripts($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $cs->renderHiddenFieldsEnd($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderScriptFilesEnd($writer);
+ $cs->renderEndScripts($writer);
+ }
+ else
+ {
+ $cs->renderHiddenFieldsBegin($writer);
+
+ $page->beginFormRender($writer);
+ $this->renderChildren($writer);
+ $page->endFormRender($writer);
+
+ $cs->renderHiddenFieldsEnd($writer);
+ }
+
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return string id path to the default button control.
+ */
+ public function getDefaultButton()
+ {
+ return $this->getViewState('DefaultButton','');
+ }
+
+ /**
+ * Sets a button to be default one in a form.
+ * A default button will be clicked if a user presses 'Enter' key within
+ * the form.
+ * @param string id path to the default button control.
+ */
+ public function setDefaultButton($value)
+ {
+ $this->setViewState('DefaultButton',$value,'');
+ }
+
+ /**
+ * @return string form submission method. Defaults to 'post'.
+ */
+ public function getMethod()
+ {
+ return $this->getViewState('Method','post');
+ }
+
+ /**
+ * @param string form submission method. Valid values include 'post' and 'get'.
+ */
+ public function setMethod($value)
+ {
+ $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post');
+ }
+
+ /**
+ * @return string the encoding type a browser uses to post data back to the server
+ */
+ public function getEnctype()
+ {
+ return $this->getViewState('Enctype','');
+ }
+
+ /**
+ * @param string the encoding type a browser uses to post data back to the server.
+ * Commonly used types include
+ * - application/x-www-form-urlencoded : Form data is encoded as name/value pairs. This is the standard encoding format.
+ * - multipart/form-data : Form data is encoded as a message with a separate part for each control on the page.
+ * - text/plain : Form data is encoded in plain text, without any control or formatting characters.
+ */
+ public function setEnctype($value)
+ {
+ $this->setViewState('Enctype',$value,'');
+ }
+
+ /**
+ * @return string form name, which is equal to {@link getUniqueID UniqueID}.
+ */
+ public function getName()
+ {
+ return $this->getUniqueID();
+ }
+}
+
diff --git a/framework/Web/UI/THtmlWriter.php b/framework/Web/UI/THtmlWriter.php
index 96e1a5e1..9e264c77 100644
--- a/framework/Web/UI/THtmlWriter.php
+++ b/framework/Web/UI/THtmlWriter.php
@@ -1,229 +1,229 @@
-<?php
-/**
- * THtmlWriter class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THtmlWriter class
- *
- * THtmlWriter is a writer that renders valid XHTML outputs.
- * It provides functions to render tags, their attributes and stylesheet fields.
- * Attribute and stylesheet values will be automatically HTML-encoded if
- * they require so. For example, the 'value' attribute in an input tag
- * will be encoded.
- *
- * A common usage of THtmlWriter is as the following sequence:
- * <code>
- * $writer->addAttribute($name1,$value1);
- * $writer->addAttribute($name2,$value2);
- * $writer->renderBeginTag($tagName);
- * // ... render contents enclosed within the tag here
- * $writer->renderEndTag();
- * </code>
- * Make sure each invocation of {@link renderBeginTag} is accompanied with
- * a {@link renderEndTag} and they are properly nested, like nesting
- * tags in HTML and XHTML.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THtmlWriter extends TApplicationComponent implements ITextWriter
-{
- /**
- * @var array list of tags are do not need a closing tag
- */
- private static $_simpleTags=array(
- 'area'=>true,
- 'base'=>true,
- 'basefont'=>true,
- 'bgsound'=>true,
- 'col'=>true,
- 'embed'=>true,
- 'frame'=>true,
- 'hr'=>true,
- 'img'=>true,
- 'input'=>true,
- 'isindex'=>true,
- 'link'=>true,
- 'meta'=>true,
- 'wbr'=>true,
- );
- /**
- * @var array list of attributes to be rendered for a tag
- */
- private $_attributes=array();
- /**
- * @var array list of openning tags
- */
- private $_openTags=array();
- /**
- * @var array list of style attributes
- */
- private $_styles=array();
- /**
- * @var ITextWriter writer
- */
- private $_writer=null;
-
- /**
- * Constructor.
- * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
- */
- public function __construct($writer)
- {
- $this->_writer=$writer;
- }
-
- public function getWriter()
- {
- return $this->_writer;
- }
-
- public function setWriter($writer)
- {
- $this->_writer = $writer;
- }
- /**
- * Adds a list of attributes to be rendered.
- * @param array list of attributes to be rendered
- */
- public function addAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds an attribute to be rendered.
- * @param string name of the attribute
- * @param string value of the attribute
- */
- public function addAttribute($name,$value)
- {
- $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named attribute from rendering
- * @param string name of the attribute to be removed
- */
- public function removeAttribute($name)
- {
- unset($this->_attributes[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Adds a list of stylesheet attributes to be rendered.
- * @param array list of stylesheet attributes to be rendered
- */
- public function addStyleAttributes($attrs)
- {
- foreach($attrs as $name=>$value)
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Adds a stylesheet attribute to be rendered
- * @param string stylesheet attribute name
- * @param string stylesheet attribute value
- */
- public function addStyleAttribute($name,$value)
- {
- $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
- }
-
- /**
- * Removes the named stylesheet attribute from rendering
- * @param string name of the stylesheet attribute to be removed
- */
- public function removeStyleAttribute($name)
- {
- unset($this->_styles[THttpUtility::htmlStrip($name)]);
- }
-
- /**
- * Flushes the rendering result.
- * This will invoke the underlying writer's flush method.
- * @return string the content being flushed
- */
- public function flush()
- {
- return $this->_writer->flush();
- }
-
- /**
- * Renders a string.
- * @param string string to be rendered
- */
- public function write($str)
- {
- $this->_writer->write($str);
- }
-
- /**
- * Renders a string and appends a newline to it.
- * @param string string to be rendered
- */
- public function writeLine($str='')
- {
- $this->_writer->write($str."\n");
- }
-
- /**
- * Renders an HTML break.
- */
- public function writeBreak()
- {
- $this->_writer->write('<br/>');
- }
-
- /**
- * Renders the openning tag.
- * @param string tag name
- */
- public function renderBeginTag($tagName)
- {
- $str='<'.$tagName;
- foreach($this->_attributes as $name=>$value)
- $str.=' '.$name.'="'.$value.'"';
- if(!empty($this->_styles))
- {
- $str.=' style="';
- foreach($this->_styles as $name=>$value)
- $str.=$name.':'.$value.';';
- $str.='"';
- }
- if(isset(self::$_simpleTags[$tagName]))
- {
- $str.=' />';
- $this->_openTags[] = '';
- }
- else
- {
- $str.='>';
- $this->_openTags[] = $tagName;
- }
- $this->_writer->write($str);
- $this->_attributes=array();
- $this->_styles=array();
- }
-
- /**
- * Renders the closing tag.
- */
- public function renderEndTag()
- {
- if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
- $this->_writer->write('</'.$tagName.'>');
- }
-}
-
+<?php
+/**
+ * THtmlWriter class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * THtmlWriter class
+ *
+ * THtmlWriter is a writer that renders valid XHTML outputs.
+ * It provides functions to render tags, their attributes and stylesheet fields.
+ * Attribute and stylesheet values will be automatically HTML-encoded if
+ * they require so. For example, the 'value' attribute in an input tag
+ * will be encoded.
+ *
+ * A common usage of THtmlWriter is as the following sequence:
+ * <code>
+ * $writer->addAttribute($name1,$value1);
+ * $writer->addAttribute($name2,$value2);
+ * $writer->renderBeginTag($tagName);
+ * // ... render contents enclosed within the tag here
+ * $writer->renderEndTag();
+ * </code>
+ * Make sure each invocation of {@link renderBeginTag} is accompanied with
+ * a {@link renderEndTag} and they are properly nested, like nesting
+ * tags in HTML and XHTML.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THtmlWriter extends TApplicationComponent implements ITextWriter
+{
+ /**
+ * @var array list of tags are do not need a closing tag
+ */
+ private static $_simpleTags=array(
+ 'area'=>true,
+ 'base'=>true,
+ 'basefont'=>true,
+ 'bgsound'=>true,
+ 'col'=>true,
+ 'embed'=>true,
+ 'frame'=>true,
+ 'hr'=>true,
+ 'img'=>true,
+ 'input'=>true,
+ 'isindex'=>true,
+ 'link'=>true,
+ 'meta'=>true,
+ 'wbr'=>true,
+ );
+ /**
+ * @var array list of attributes to be rendered for a tag
+ */
+ private $_attributes=array();
+ /**
+ * @var array list of openning tags
+ */
+ private $_openTags=array();
+ /**
+ * @var array list of style attributes
+ */
+ private $_styles=array();
+ /**
+ * @var ITextWriter writer
+ */
+ private $_writer=null;
+
+ /**
+ * Constructor.
+ * @param ITextWriter a writer that THtmlWriter will pass its rendering result to
+ */
+ public function __construct($writer)
+ {
+ $this->_writer=$writer;
+ }
+
+ public function getWriter()
+ {
+ return $this->_writer;
+ }
+
+ public function setWriter($writer)
+ {
+ $this->_writer = $writer;
+ }
+ /**
+ * Adds a list of attributes to be rendered.
+ * @param array list of attributes to be rendered
+ */
+ public function addAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds an attribute to be rendered.
+ * @param string name of the attribute
+ * @param string value of the attribute
+ */
+ public function addAttribute($name,$value)
+ {
+ $this->_attributes[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named attribute from rendering
+ * @param string name of the attribute to be removed
+ */
+ public function removeAttribute($name)
+ {
+ unset($this->_attributes[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Adds a list of stylesheet attributes to be rendered.
+ * @param array list of stylesheet attributes to be rendered
+ */
+ public function addStyleAttributes($attrs)
+ {
+ foreach($attrs as $name=>$value)
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Adds a stylesheet attribute to be rendered
+ * @param string stylesheet attribute name
+ * @param string stylesheet attribute value
+ */
+ public function addStyleAttribute($name,$value)
+ {
+ $this->_styles[THttpUtility::htmlStrip($name)]=THttpUtility::htmlEncode($value);
+ }
+
+ /**
+ * Removes the named stylesheet attribute from rendering
+ * @param string name of the stylesheet attribute to be removed
+ */
+ public function removeStyleAttribute($name)
+ {
+ unset($this->_styles[THttpUtility::htmlStrip($name)]);
+ }
+
+ /**
+ * Flushes the rendering result.
+ * This will invoke the underlying writer's flush method.
+ * @return string the content being flushed
+ */
+ public function flush()
+ {
+ return $this->_writer->flush();
+ }
+
+ /**
+ * Renders a string.
+ * @param string string to be rendered
+ */
+ public function write($str)
+ {
+ $this->_writer->write($str);
+ }
+
+ /**
+ * Renders a string and appends a newline to it.
+ * @param string string to be rendered
+ */
+ public function writeLine($str='')
+ {
+ $this->_writer->write($str."\n");
+ }
+
+ /**
+ * Renders an HTML break.
+ */
+ public function writeBreak()
+ {
+ $this->_writer->write('<br/>');
+ }
+
+ /**
+ * Renders the openning tag.
+ * @param string tag name
+ */
+ public function renderBeginTag($tagName)
+ {
+ $str='<'.$tagName;
+ foreach($this->_attributes as $name=>$value)
+ $str.=' '.$name.'="'.$value.'"';
+ if(!empty($this->_styles))
+ {
+ $str.=' style="';
+ foreach($this->_styles as $name=>$value)
+ $str.=$name.':'.$value.';';
+ $str.='"';
+ }
+ if(isset(self::$_simpleTags[$tagName]))
+ {
+ $str.=' />';
+ $this->_openTags[] = '';
+ }
+ else
+ {
+ $str.='>';
+ $this->_openTags[] = $tagName;
+ }
+ $this->_writer->write($str);
+ $this->_attributes=array();
+ $this->_styles=array();
+ }
+
+ /**
+ * Renders the closing tag.
+ */
+ public function renderEndTag()
+ {
+ if(!empty($this->_openTags) && ($tagName=array_pop($this->_openTags))!=='')
+ $this->_writer->write('</'.$tagName.'>');
+ }
+}
+
diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php
index 37326031..26a06b64 100644
--- a/framework/Web/UI/TPage.php
+++ b/framework/Web/UI/TPage.php
@@ -1,1341 +1,1341 @@
-<?php
-/**
- * TPage class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-Prado::using('System.Web.UI.WebControls.*');
-Prado::using('System.Web.UI.TControl');
-Prado::using('System.Web.UI.WebControls.TWebControl');
-Prado::using('System.Web.UI.TCompositeControl');
-Prado::using('System.Web.UI.TTemplateControl');
-Prado::using('System.Web.UI.TForm');
-Prado::using('System.Web.UI.TClientScriptManager');
-
-/**
- * TPage class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TPage extends TTemplateControl
-{
- /**
- * system post fields
- */
- const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
- const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
- const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
- const FIELD_PAGESTATE='PRADO_PAGESTATE';
- const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
- const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
-
- /**
- * @var array system post fields
- */
- private static $_systemPostFields=array(
- 'PRADO_POSTBACK_TARGET'=>true,
- 'PRADO_POSTBACK_PARAMETER'=>true,
- 'PRADO_LASTFOCUS'=>true,
- 'PRADO_PAGESTATE'=>true,
- 'PRADO_CALLBACK_TARGET'=>true,
- 'PRADO_CALLBACK_PARAMETER'=>true
- );
- /**
- * @var TForm form instance
- */
- private $_form;
- /**
- * @var THead head instance
- */
- private $_head;
- /**
- * @var array list of registered validators
- */
- private $_validators=array();
- /**
- * @var boolean if validation has been performed
- */
- private $_validated=false;
- /**
- * @var TTheme page theme
- */
- private $_theme;
- /**
- * @var string page title set when Head is not in page yet
- */
- private $_title;
- /**
- * @var TTheme page stylesheet theme
- */
- private $_styleSheet;
- /**
- * @var TClientScriptManager client script manager
- */
- private $_clientScript;
- /**
- * @var TMap data post back by user
- */
- protected $_postData;
- /**
- * @var TMap postback data that is not handled during first invocation of LoadPostData.
- */
- protected $_restPostData;
- /**
- * @var array list of controls whose data have been changed due to the postback
- */
- protected $_controlsPostDataChanged=array();
- /**
- * @var array list of controls that need to load post data in the current request
- */
- protected $_controlsRequiringPostData=array();
- /**
- * @var array list of controls that need to load post data in the next postback
- */
- protected $_controlsRegisteredForPostData=array();
- /**
- * @var TControl control that needs to raise postback event
- */
- private $_postBackEventTarget;
- /**
- * @var string postback event parameter
- */
- private $_postBackEventParameter;
- /**
- * @var boolean whether the form has been rendered
- */
- protected $_formRendered=false;
- /**
- * @var boolean whether the current rendering is within a form
- */
- protected $_inFormRender=false;
- /**
- * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
- */
- private $_focus;
- /**
- * @var string page path to this page
- */
- private $_pagePath='';
- /**
- * @var boolean whether page state should be HMAC validated
- */
- private $_enableStateValidation=true;
- /**
- * @var boolean whether page state should be encrypted
- */
- private $_enableStateEncryption=false;
- /**
- * @var boolean whether page state should be compressed
- * @since 3.1.6
- */
- private $_enableStateCompression=true;
- /**
- * @var string page state persister class name
- */
- private $_statePersisterClass='System.Web.UI.TPageStatePersister';
- /**
- * @var mixed page state persister
- */
- private $_statePersister;
- /**
- * @var TStack stack used to store currently active caching controls
- */
- private $_cachingStack;
- /**
- * @var string state string to be stored on the client side
- */
- private $_clientState='';
- /**
- * @var array post data loader IDs.
- */
- protected $_postDataLoaders=array();
- /**
- * @var boolean true if loading post data.
- */
- protected $_isLoadingPostData=false;
- /**
- * @var boolean whether client supports javascript
- */
- private $_enableJavaScript=true;
- /**
- * @var THtmlWriter current html render writer
- */
- private $_writer;
-
- /**
- * Constructor.
- * Sets the page object to itself.
- * Derived classes must call parent implementation.
- */
- public function __construct()
- {
- $this->setPage($this);
- }
-
- /**
- * Runs through the page lifecycles.
- * @param THtmlTextWriter the HTML writer
- */
- public function run($writer)
- {
- Prado::trace("Running page life cycles",'System.Web.UI.TPage');
- $this->_writer = $writer;
-
- $this->determinePostBackMode();
-
- if($this->getIsPostBack())
- {
- if($this->getIsCallback())
- $this->processCallbackRequest($writer);
- else
- $this->processPostBackRequest($writer);
- }
- else
- $this->processNormalRequest($writer);
-
- $this->_writer = null;
- }
-
- protected function processNormalRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected function processPostBackRequest($writer)
- {
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- protected static function decodeUTF8($data, $enc)
- {
- if(is_array($data))
- {
- foreach($data as $k=>$v)
- $data[$k]=self::decodeUTF8($v, $enc);
- return $data;
- } elseif(is_string($data)) {
- return iconv('UTF-8',$enc.'//IGNORE',$data);
- } else {
- return $data;
- }
- }
-
- /**
- * Sets Adapter to TActivePageAdapter and calls apter to process the
- * callback request.
- */
- protected function processCallbackRequest($writer)
- {
- Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
-
- $this->setAdapter(new TActivePageAdapter($this));
-
- // Decode Callback postData from UTF-8 to current Charset
- if (($g=$this->getApplication()->getGlobalization(false))!==null &&
- strtoupper($enc=$g->getCharset())!='UTF-8')
- foreach ($this->_postData as $k=>$v)
- $this->_postData[$k]=self::decodeUTF8($v, $enc);
-
- Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
- $this->onPreInit(null);
-
- Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
- $this->initRecursive();
-
- Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
- $this->onInitComplete(null);
-
- $this->_restPostData=new TMap;
- Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
- $this->loadPageState();
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_postData,true);
- Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
- $this->onPreLoad(null);
- Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
- $this->loadRecursive();
-
- Prado::trace("Page processPostData()",'System.Web.UI.TPage');
- $this->processPostData($this->_restPostData,false);
-
- Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
- $this->raiseChangedEvents();
-
-
- $this->getAdapter()->processCallbackEvent($writer);
-
-/*
- Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
- $this->raisePostBackEvent();
-*/
- Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
- $this->onLoadComplete(null);
-
- Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
- $this->preRenderRecursive();
- Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
- $this->onPreRenderComplete(null);
-
- Prado::trace("Page savePageState()",'System.Web.UI.TPage');
- $this->savePageState();
- Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
- $this->onSaveStateComplete(null);
-
-/*
- Prado::trace("Page renderControl()",'System.Web.UI.TPage');
- $this->renderControl($writer);
-*/
- $this->getAdapter()->renderCallbackResponse($writer);
-
- Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
- $this->unloadRecursive();
- }
-
- /**
- * Gets the callback client script handler that allows javascript functions
- * to be executed during the callback response.
- * @return TCallbackClientScript interface to client-side javascript code.
- */
- public function getCallbackClient()
- {
- if($this->getAdapter() !== null)
- return $this->getAdapter()->getCallbackClientHandler();
- else
- return new TCallbackClientScript();
- }
-
- /**
- * Set a new callback client handler.
- * @param TCallbackClientScript new callback client script handler.
- */
- public function setCallbackClient($client)
- {
- $this->getAdapter()->setCallbackClientHandler($client);
- }
-
- /**
- * @return TControl the control responsible for the current callback event,
- * null if nonexistent
- */
- public function getCallbackEventTarget()
- {
- return $this->getAdapter()->getCallbackEventTarget();
- }
-
- /**
- * Registers a control to raise callback event in the current request.
- * @param TControl control registered to raise callback event.
- */
- public function setCallbackEventTarget(TControl $control)
- {
- $this->getAdapter()->setCallbackEventTarget($control);
- }
-
- /**
- * Callback parameter is decoded assuming JSON encoding.
- * @return string callback event parameter
- */
- public function getCallbackEventParameter()
- {
- return $this->getAdapter()->getCallbackEventParameter();
- }
-
- /**
- * @param mixed callback event parameter
- */
- public function setCallbackEventParameter($value)
- {
- $this->getAdapter()->setCallbackEventParameter($value);
- }
-
- /**
- * Register post data loaders for Callback to collect post data.
- * This method should only be called by framework developers.
- * @param TControl control that requires post data.
- * @see TControl::preRenderRecursive();
- */
- public function registerPostDataLoader($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_postDataLoaders[$id] = true;
- }
-
- /**
- * Get a list of IDs of controls that are enabled and require post data.
- * @return array list of IDs implementing IPostBackDataHandler
- */
- public function getPostDataLoaders()
- {
- return array_keys($this->_postDataLoaders);
- }
-
- /**
- * @return TForm the form on the page
- */
- public function getForm()
- {
- return $this->_form;
- }
-
- /**
- * Registers a TForm instance to the page.
- * Note, a page can contain at most one TForm instance.
- * @param TForm the form on the page
- * @throws TInvalidOperationException if this method is invoked twice or more.
- */
- public function setForm(TForm $form)
- {
- if($this->_form===null)
- $this->_form=$form;
- else
- throw new TInvalidOperationException('page_form_duplicated');
- }
-
- /**
- * Returns a list of registered validators.
- * If validation group is specified, only the validators in that group will be returned.
- * @param string validation group
- * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
- */
- public function getValidators($validationGroup=null)
- {
- if(!$this->_validators)
- $this->_validators=new TList;
- if(empty($validationGroup) === true)
- return $this->_validators;
- else
- {
- $list=new TList;
- foreach($this->_validators as $validator)
- if($validator->getValidationGroup()===$validationGroup)
- $list->add($validator);
- return $list;
- }
- }
-
- /**
- * Performs input validation.
- * This method will invoke the registered validators to perform the actual validation.
- * If validation group is specified, only the validators in that group will be invoked.
- * @param string validation group. If null, all validators will perform validation.
- */
- public function validate($validationGroup=null)
- {
- Prado::trace("Page validate()",'System.Web.UI.TPage');
- $this->_validated=true;
- if($this->_validators && $this->_validators->getCount())
- {
- if($validationGroup===null)
- {
- foreach($this->_validators as $validator)
- $validator->validate();
- }
- else
- {
- foreach($this->_validators as $validator)
- {
- if($validator->getValidationGroup()===$validationGroup)
- $validator->validate();
- }
- }
- }
- }
-
- /**
- * Returns whether user input is valid or not.
- * This method must be invoked after {@link validate} is called.
- * @return boolean whether the user input is valid or not.
- * @throws TInvalidOperationException if {@link validate} is not invoked yet.
- */
- public function getIsValid()
- {
- if($this->_validated)
- {
- if($this->_validators && $this->_validators->getCount())
- {
- foreach($this->_validators as $validator)
- if(!$validator->getIsValid())
- return false;
- }
- return true;
- }
- else
- throw new TInvalidOperationException('page_isvalid_unknown');
- }
-
- /**
- * @return TTheme the theme used for the page. Defaults to null.
- */
- public function getTheme()
- {
- if(is_string($this->_theme))
- $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
- return $this->_theme;
- }
-
- /**
- * Sets the theme to be used for the page.
- * @param string|TTheme the theme name or the theme object to be used for the page.
- */
- public function setTheme($value)
- {
- $this->_theme=empty($value)?null:$value;
- }
-
-
- /**
- * @return TTheme the stylesheet theme used for the page. Defaults to null.
- */
- public function getStyleSheetTheme()
- {
- if(is_string($this->_styleSheet))
- $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
- return $this->_styleSheet;
- }
-
- /**
- * Sets the stylesheet theme to be used for the page.
- * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
- */
- public function setStyleSheetTheme($value)
- {
- $this->_styleSheet=empty($value)?null:$value;
- }
-
- /**
- * Applies a skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied skin with
- */
- public function applyControlSkin($control)
- {
- if(($theme=$this->getTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * Applies a stylesheet skin in the current theme to a control.
- * This method should only be used by framework developers.
- * @param TControl a control to be applied stylesheet skin with
- */
- public function applyControlStyleSheet($control)
- {
- if(($theme=$this->getStyleSheetTheme())!==null)
- $theme->applySkin($control);
- }
-
- /**
- * @return TClientScriptManager client script manager
- */
- public function getClientScript()
- {
- if(!$this->_clientScript) {
- $className = $classPath = $this->getService()->getClientScriptManagerClass();
- Prado::using($className);
- if(($pos=strrpos($className,'.'))!==false)
- $className=substr($className,$pos+1);
-
- if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
- throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
-
- $this->_clientScript=new $className($this);
- }
- return $this->_clientScript;
- }
-
- /**
- * Raises OnPreInit event.
- * This method is invoked right before {@link onInit OnInit} stage.
- * You may override this method to provide additional initialization that
- * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
- * {@link setStyleSheetTheme StyleSheetTheme}).
- * Remember to call the parent implementation to ensure OnPreInit event is raised.
- * @param mixed event parameter
- */
- public function onPreInit($param)
- {
- $this->raiseEvent('OnPreInit',$this,$param);
- }
-
- /**
- * Raises OnInitComplete event.
- * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional initialization that
- * should be done after {@link onInit OnInit}.
- * Remember to call the parent implementation to ensure OnInitComplete event is raised.
- * @param mixed event parameter
- */
- public function onInitComplete($param)
- {
- $this->raiseEvent('OnInitComplete',$this,$param);
- }
-
- /**
- * Raises OnPreLoad event.
- * This method is invoked right before {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done before {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnPreLoad event is raised.
- * @param mixed event parameter
- */
- public function onPreLoad($param)
- {
- $this->raiseEvent('OnPreLoad',$this,$param);
- }
-
- /**
- * Raises OnLoadComplete event.
- * This method is invoked right after {@link onLoad OnLoad} stage.
- * You may override this method to provide additional page loading logic that
- * should be done after {@link onLoad OnLoad}.
- * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
- * @param mixed event parameter
- */
- public function onLoadComplete($param)
- {
- $this->raiseEvent('OnLoadComplete',$this,$param);
- }
-
- /**
- * Raises OnPreRenderComplete event.
- * This method is invoked right after {@link onPreRender OnPreRender} stage.
- * You may override this method to provide additional preparation for page rendering
- * that should be done after {@link onPreRender OnPreRender}.
- * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
- * @param mixed event parameter
- */
- public function onPreRenderComplete($param)
- {
- $this->raiseEvent('OnPreRenderComplete',$this,$param);
- $cs=$this->getClientScript();
- $theme=$this->getTheme();
- if($theme instanceof ITheme)
- {
- foreach($theme->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($theme->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
- $styleSheet=$this->getStyleSheetTheme();
- if($styleSheet instanceof ITheme)
- {
- foreach($styleSheet->getStyleSheetFiles() as $url)
- $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
- foreach($styleSheet->getJavaScriptFiles() as $url)
- $cs->registerHeadScriptFile($url,$url);
- }
-
- if($cs->getRequiresHead() && $this->getHead()===null)
- throw new TConfigurationException('page_head_required');
- }
-
- /**
- * Determines the media type of the CSS file.
- * The media type is determined according to the following file name pattern:
- * xxx.media-type.extension
- * For example, 'mystyle.print.css' means its media type is 'print'.
- * @param string CSS URL
- * @return string media type of the CSS file
- */
- private function getCssMediaType($url)
- {
- $segs=explode('.',basename($url));
- if(isset($segs[2]))
- return $segs[count($segs)-2];
- else
- return '';
- }
-
- /**
- * Raises OnSaveStateComplete event.
- * This method is invoked right after {@link onSaveState OnSaveState} stage.
- * You may override this method to provide additional logic after page state is saved.
- * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
- * @param mixed event parameter
- */
- public function onSaveStateComplete($param)
- {
- $this->raiseEvent('OnSaveStateComplete',$this,$param);
- }
-
- /**
- * Determines whether the current page request is a postback.
- * Call {@link getIsPostBack} to get the result.
- */
- private function determinePostBackMode()
- {
- $postData=$this->getRequest();
- if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
- $this->_postData=$postData;
- }
-
- /**
- * @return boolean whether the current page request is a postback
- */
- public function getIsPostBack()
- {
- return $this->_postData!==null;
- }
-
- /**
- * @return boolean whether this is a callback request
- */
- public function getIsCallback()
- {
- return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
- }
-
- /**
- * This method is invoked when control state is to be saved.
- * You can override this method to do last step state saving.
- * Parent implementation must be invoked.
- */
- public function saveState()
- {
- parent::saveState();
- $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
- }
-
- /**
- * This method is invoked right after the control has loaded its state.
- * You can override this method to initialize data from the control state.
- * Parent implementation must be invoked.
- */
- public function loadState()
- {
- parent::loadState();
- $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
- }
-
- /**
- * Loads page state from persistent storage.
- */
- protected function loadPageState()
- {
- Prado::trace("Loading state",'System.Web.UI.TPage');
- $state=$this->getStatePersister()->load();
- $this->loadStateRecursive($state,$this->getEnableViewState());
- }
-
- /**
- * Saves page state from persistent storage.
- */
- protected function savePageState()
- {
- Prado::trace("Saving state",'System.Web.UI.TPage');
- $state=&$this->saveStateRecursive($this->getEnableViewState());
- $this->getStatePersister()->save($state);
- }
-
- /**
- * @param string the field name
- * @return boolean whether the specified field is a system field in postback data
- */
- protected function isSystemPostField($field)
- {
- return isset(self::$_systemPostFields[$field]);
- }
-
- /**
- * Registers a control for loading post data in the next postback.
- * This method needs to be invoked if the control to load post data
- * may not have a post variable in some cases. For example, a checkbox,
- * if not checked, will not have a post value.
- * @param TControl control registered for loading post data
- */
- public function registerRequiresPostData($control)
- {
- $id=is_string($control)?$control:$control->getUniqueID();
- $this->_controlsRegisteredForPostData[$id]=true;
- $this->registerPostDataLoader($id);
- $params=func_get_args();
- foreach($this->getCachingStack() as $item)
- $item->registerAction('Page','registerRequiresPostData',array($id));
- }
-
- /**
- * @return TControl the control responsible for the current postback event, null if nonexistent
- */
- public function getPostBackEventTarget()
- {
- if($this->_postBackEventTarget===null && $this->_postData!==null)
- {
- $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
- if(!empty($eventTarget))
- $this->_postBackEventTarget=$this->findControl($eventTarget);
- }
- return $this->_postBackEventTarget;
- }
-
- /**
- * Registers a control to raise postback event in the current request.
- * @param TControl control registered to raise postback event.
- */
- public function setPostBackEventTarget(TControl $control)
- {
- $this->_postBackEventTarget=$control;
- }
-
- /**
- * @return string postback event parameter
- */
- public function getPostBackEventParameter()
- {
- if($this->_postBackEventParameter===null && $this->_postData!==null)
- {
- if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
- $this->_postBackEventParameter='';
- }
- return $this->_postBackEventParameter;
- }
-
- /**
- * @param string postback event parameter
- */
- public function setPostBackEventParameter($value)
- {
- $this->_postBackEventParameter=$value;
- }
-
- /**
- * Processes post data.
- * @param TMap post data to be processed
- * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
- */
- protected function processPostData($postData,$beforeLoad)
- {
- $this->_isLoadingPostData=true;
- if($beforeLoad)
- $this->_restPostData=new TMap;
- foreach($postData as $key=>$value)
- {
- if($this->isSystemPostField($key))
- continue;
- else if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else if($control instanceof IPostBackEventHandler &&
- empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
- {
- $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
- }
- unset($this->_controlsRequiringPostData[$key]);
- }
- else if($beforeLoad)
- $this->_restPostData->add($key,$value);
- }
-
- foreach($this->_controlsRequiringPostData as $key=>$value)
- {
- if($control=$this->findControl($key))
- {
- if($control instanceof IPostBackDataHandler)
- {
- if($control->loadPostData($key,$this->_postData))
- $this->_controlsPostDataChanged[]=$control;
- }
- else
- throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
- unset($this->_controlsRequiringPostData[$key]);
- }
- }
- $this->_isLoadingPostData=false;
- }
-
- /**
- * @return boolean true if loading post data.
- */
- public function getIsLoadingPostData()
- {
- return $this->_isLoadingPostData;
- }
-
- /**
- * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
- */
- protected function raiseChangedEvents()
- {
- foreach($this->_controlsPostDataChanged as $control)
- $control->raisePostDataChangedEvent();
- }
-
- /**
- * Raises PostBack event.
- */
- protected function raisePostBackEvent()
- {
- if(($postBackHandler=$this->getPostBackEventTarget())===null)
- $this->validate();
- else if($postBackHandler instanceof IPostBackEventHandler)
- $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
- }
-
- /**
- * @return boolean Whether form rendering is in progress
- */
- public function getInFormRender()
- {
- return $this->_inFormRender;
- }
-
- /**
- * Ensures the control is rendered within a form.
- * @param TControl the control to be rendered
- * @throws TConfigurationException if the control is outside of the form
- */
- public function ensureRenderInForm($control)
- {
- if(!$this->getIsCallback() && !$this->_inFormRender)
- throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
- }
-
- /**
- * @internal This method is invoked by TForm at the beginning of its rendering
- */
- public function beginFormRender($writer)
- {
- if($this->_formRendered)
- throw new TConfigurationException('page_form_duplicated');
- $this->_formRendered=true;
- $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
- $this->_inFormRender=true;
- }
-
- /**
- * @internal This method is invoked by TForm at the end of its rendering
- */
- public function endFormRender($writer)
- {
- if($this->_focus)
- {
- if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
- $focus=$this->_focus->getClientID();
- else
- $focus=$this->_focus;
- $this->getClientScript()->registerFocusControl($focus);
- }
- else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
- $this->getClientScript()->registerFocusControl($lastFocus);
- $this->_inFormRender=false;
- }
-
- /**
- * Sets input focus on a control after the page is rendered to users.
- * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
- */
- public function setFocus($value)
- {
- $this->_focus=$value;
- }
-
- /**
- * @return boolean whether client supports javascript. Defaults to true.
- */
- public function getClientSupportsJavaScript()
- {
- return $this->_enableJavaScript;
- }
-
- /**
- * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
- */
- public function setClientSupportsJavaScript($value)
- {
- $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return THead page head, null if not available
- */
- public function getHead()
- {
- return $this->_head;
- }
-
- /**
- * @param THead page head
- * @throws TInvalidOperationException if a head already exists
- */
- public function setHead(THead $value)
- {
- if($this->_head)
- throw new TInvalidOperationException('page_head_duplicated');
- $this->_head=$value;
- if($this->_title!==null)
- {
- $this->_head->setTitle($this->_title);
- $this->_title=null;
- }
- }
-
- /**
- * @return string page title.
- */
- public function getTitle()
- {
- if($this->_head)
- return $this->_head->getTitle();
- else
- return $this->_title===null ? '' : $this->_title;
- }
-
- /**
- * Sets the page title.
- * Note, a {@link THead} control needs to place on the page
- * in order that this title be rendered.
- * @param string page title. This will override the title set in {@link getHead Head}.
- */
- public function setTitle($value)
- {
- if($this->_head)
- $this->_head->setTitle($value);
- else
- $this->_title=$value;
- }
-
- /**
- * Returns the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @return string the state to be stored on the client side
- */
- public function getClientState()
- {
- return $this->_clientState;
- }
-
- /**
- * Sets the state to be stored on the client side.
- * This method should only be used by framework and control developers.
- * @param string the state to be stored on the client side
- */
- public function setClientState($state)
- {
- $this->_clientState=$state;
- }
-
- /**
- * @return string the state postback from client side
- */
- public function getRequestClientState()
- {
- return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
- }
-
- /**
- * @return string class name of the page state persister. Defaults to TPageStatePersister.
- */
- public function getStatePersisterClass()
- {
- return $this->_statePersisterClass;
- }
-
- /**
- * @param string class name of the page state persister.
- */
- public function setStatePersisterClass($value)
- {
- $this->_statePersisterClass=$value;
- }
-
- /**
- * @return IPageStatePersister page state persister
- */
- public function getStatePersister()
- {
- if($this->_statePersister===null)
- {
- $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
- if(!($this->_statePersister instanceof IPageStatePersister))
- throw new TInvalidDataTypeException('page_statepersister_invalid');
- $this->_statePersister->setPage($this);
- }
- return $this->_statePersister;
- }
-
- /**
- * @return boolean whether page state should be HMAC validated. Defaults to true.
- */
- public function getEnableStateValidation()
- {
- return $this->_enableStateValidation;
- }
-
- /**
- * @param boolean whether page state should be HMAC validated.
- */
- public function setEnableStateValidation($value)
- {
- $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be encrypted. Defaults to false.
- */
- public function getEnableStateEncryption()
- {
- return $this->_enableStateEncryption;
- }
-
- /**
- * @param boolean whether page state should be encrypted.
- */
- public function setEnableStateEncryption($value)
- {
- $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether page state should be compressed. Defaults to true.
- * @since 3.1.6
- */
- public function getEnableStateCompression()
- {
- return $this->_enableStateCompression;
- }
-
- /**
- * @param boolean whether page state should be compressed.
- * @since 3.1.6
- */
- public function setEnableStateCompression($value)
- {
- $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return string the requested page path for this page
- */
- public function getPagePath()
- {
- return $this->_pagePath;
- }
-
- /**
- * @param string the requested page path for this page
- */
- public function setPagePath($value)
- {
- $this->_pagePath=$value;
- }
-
- /**
- * Registers an action associated with the content being cached.
- * The registered action will be replayed if the content stored
- * in the cache is served to end-users.
- * @param string context of the action method. This is a property-path
- * referring to the context object (e.g. Page, Page.ClientScript).
- * @param string method name of the context object
- * @param array list of parameters to be passed to the action method
- */
- public function registerCachingAction($context,$funcName,$funcParams)
- {
- if($this->_cachingStack)
- {
- foreach($this->_cachingStack as $cache)
- $cache->registerAction($context,$funcName,$funcParams);
- }
- }
-
- /**
- * @return TStack stack of {@link TOutputCache} objects
- */
- public function getCachingStack()
- {
- if(!$this->_cachingStack)
- $this->_cachingStack=new TStack;
- return $this->_cachingStack;
- }
-
- /**
- * Flushes output
- */
- public function flushWriter()
- {
- if ($this->_writer)
- $this->Response->write($this->_writer->flush());
- }
-}
-
-/**
- * IPageStatePersister interface.
- *
- * IPageStatePersister interface is required for all page state persister
- * classes.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1
- */
-interface IPageStatePersister
-{
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage();
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page);
- /**
- * Saves state to persistent storage.
- * @param mixed state to be stored
- */
- public function save($state);
- /**
- * Loads page state from persistent storage
- * @return mixed the restored state
- */
- public function load();
-}
-
-
-/**
- * TPageStateFormatter class.
- *
- * TPageStateFormatter is a utility class to transform the page state
- * into and from a string that can be properly saved in persistent storage.
- *
- * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
- * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
- * TPageStateFormatter may do HMAC validation and encryption to prevent
- * the state data from being tampered or viewed.
- * The private keys and hashing/encryption methods are determined by
- * {@link TApplication::getSecurityManager() SecurityManager}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Revision: $ $Date: $
- * @package System.Web.UI
- * @since 3.1
- */
-class TPageStateFormatter
-{
- /**
- * @param TPage
- * @param mixed state data
- * @return string serialized data
- */
- public static function serialize($page,$data)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateValidation())
- $str=$sm->hashData(Prado::serialize($data));
- else
- $str=Prado::serialize($data);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=gzcompress($str);
- if($page->getEnableStateEncryption())
- $str=$sm->encrypt($str);
- return base64_encode($str);
- }
-
- /**
- * @param TPage
- * @param string serialized data
- * @return mixed unserialized state data, null if data is corrupted
- */
- public static function unserialize($page,$data)
- {
- $str=base64_decode($data);
- if($str==='')
- return null;
- if($str!==false)
- {
- $sm=$page->getApplication()->getSecurityManager();
- if($page->getEnableStateEncryption())
- $str=$sm->decrypt($str);
- if($page->getEnableStateCompression() && extension_loaded('zlib'))
- $str=@gzuncompress($str);
- if($page->getEnableStateValidation())
- {
- if(($str=$sm->validateData($str))!==false)
- return Prado::unserialize($str);
- }
- else
- return Prado::unserialize($str);
- }
- return null;
- }
-}
+<?php
+/**
+ * TPage class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.UI.WebControls.*');
+Prado::using('System.Web.UI.TControl');
+Prado::using('System.Web.UI.WebControls.TWebControl');
+Prado::using('System.Web.UI.TCompositeControl');
+Prado::using('System.Web.UI.TTemplateControl');
+Prado::using('System.Web.UI.TForm');
+Prado::using('System.Web.UI.TClientScriptManager');
+
+/**
+ * TPage class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPage extends TTemplateControl
+{
+ /**
+ * system post fields
+ */
+ const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET';
+ const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER';
+ const FIELD_LASTFOCUS='PRADO_LASTFOCUS';
+ const FIELD_PAGESTATE='PRADO_PAGESTATE';
+ const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET';
+ const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER';
+
+ /**
+ * @var array system post fields
+ */
+ private static $_systemPostFields=array(
+ 'PRADO_POSTBACK_TARGET'=>true,
+ 'PRADO_POSTBACK_PARAMETER'=>true,
+ 'PRADO_LASTFOCUS'=>true,
+ 'PRADO_PAGESTATE'=>true,
+ 'PRADO_CALLBACK_TARGET'=>true,
+ 'PRADO_CALLBACK_PARAMETER'=>true
+ );
+ /**
+ * @var TForm form instance
+ */
+ private $_form;
+ /**
+ * @var THead head instance
+ */
+ private $_head;
+ /**
+ * @var array list of registered validators
+ */
+ private $_validators=array();
+ /**
+ * @var boolean if validation has been performed
+ */
+ private $_validated=false;
+ /**
+ * @var TTheme page theme
+ */
+ private $_theme;
+ /**
+ * @var string page title set when Head is not in page yet
+ */
+ private $_title;
+ /**
+ * @var TTheme page stylesheet theme
+ */
+ private $_styleSheet;
+ /**
+ * @var TClientScriptManager client script manager
+ */
+ private $_clientScript;
+ /**
+ * @var TMap data post back by user
+ */
+ protected $_postData;
+ /**
+ * @var TMap postback data that is not handled during first invocation of LoadPostData.
+ */
+ protected $_restPostData;
+ /**
+ * @var array list of controls whose data have been changed due to the postback
+ */
+ protected $_controlsPostDataChanged=array();
+ /**
+ * @var array list of controls that need to load post data in the current request
+ */
+ protected $_controlsRequiringPostData=array();
+ /**
+ * @var array list of controls that need to load post data in the next postback
+ */
+ protected $_controlsRegisteredForPostData=array();
+ /**
+ * @var TControl control that needs to raise postback event
+ */
+ private $_postBackEventTarget;
+ /**
+ * @var string postback event parameter
+ */
+ private $_postBackEventParameter;
+ /**
+ * @var boolean whether the form has been rendered
+ */
+ protected $_formRendered=false;
+ /**
+ * @var boolean whether the current rendering is within a form
+ */
+ protected $_inFormRender=false;
+ /**
+ * @var TControl|string the control or the ID of the element on the page to be focused when the page is sent back to user
+ */
+ private $_focus;
+ /**
+ * @var string page path to this page
+ */
+ private $_pagePath='';
+ /**
+ * @var boolean whether page state should be HMAC validated
+ */
+ private $_enableStateValidation=true;
+ /**
+ * @var boolean whether page state should be encrypted
+ */
+ private $_enableStateEncryption=false;
+ /**
+ * @var boolean whether page state should be compressed
+ * @since 3.1.6
+ */
+ private $_enableStateCompression=true;
+ /**
+ * @var string page state persister class name
+ */
+ private $_statePersisterClass='System.Web.UI.TPageStatePersister';
+ /**
+ * @var mixed page state persister
+ */
+ private $_statePersister;
+ /**
+ * @var TStack stack used to store currently active caching controls
+ */
+ private $_cachingStack;
+ /**
+ * @var string state string to be stored on the client side
+ */
+ private $_clientState='';
+ /**
+ * @var array post data loader IDs.
+ */
+ protected $_postDataLoaders=array();
+ /**
+ * @var boolean true if loading post data.
+ */
+ protected $_isLoadingPostData=false;
+ /**
+ * @var boolean whether client supports javascript
+ */
+ private $_enableJavaScript=true;
+ /**
+ * @var THtmlWriter current html render writer
+ */
+ private $_writer;
+
+ /**
+ * Constructor.
+ * Sets the page object to itself.
+ * Derived classes must call parent implementation.
+ */
+ public function __construct()
+ {
+ $this->setPage($this);
+ }
+
+ /**
+ * Runs through the page lifecycles.
+ * @param THtmlTextWriter the HTML writer
+ */
+ public function run($writer)
+ {
+ Prado::trace("Running page life cycles",'System.Web.UI.TPage');
+ $this->_writer = $writer;
+
+ $this->determinePostBackMode();
+
+ if($this->getIsPostBack())
+ {
+ if($this->getIsCallback())
+ $this->processCallbackRequest($writer);
+ else
+ $this->processPostBackRequest($writer);
+ }
+ else
+ $this->processNormalRequest($writer);
+
+ $this->_writer = null;
+ }
+
+ protected function processNormalRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected function processPostBackRequest($writer)
+ {
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ protected static function decodeUTF8($data, $enc)
+ {
+ if(is_array($data))
+ {
+ foreach($data as $k=>$v)
+ $data[$k]=self::decodeUTF8($v, $enc);
+ return $data;
+ } elseif(is_string($data)) {
+ return iconv('UTF-8',$enc.'//IGNORE',$data);
+ } else {
+ return $data;
+ }
+ }
+
+ /**
+ * Sets Adapter to TActivePageAdapter and calls apter to process the
+ * callback request.
+ */
+ protected function processCallbackRequest($writer)
+ {
+ Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter');
+
+ $this->setAdapter(new TActivePageAdapter($this));
+
+ // Decode Callback postData from UTF-8 to current Charset
+ if (($g=$this->getApplication()->getGlobalization(false))!==null &&
+ strtoupper($enc=$g->getCharset())!='UTF-8')
+ foreach ($this->_postData as $k=>$v)
+ $this->_postData[$k]=self::decodeUTF8($v, $enc);
+
+ Prado::trace("Page onPreInit()",'System.Web.UI.TPage');
+ $this->onPreInit(null);
+
+ Prado::trace("Page initRecursive()",'System.Web.UI.TPage');
+ $this->initRecursive();
+
+ Prado::trace("Page onInitComplete()",'System.Web.UI.TPage');
+ $this->onInitComplete(null);
+
+ $this->_restPostData=new TMap;
+ Prado::trace("Page loadPageState()",'System.Web.UI.TPage');
+ $this->loadPageState();
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_postData,true);
+ Prado::trace("Page onPreLoad()",'System.Web.UI.TPage');
+ $this->onPreLoad(null);
+ Prado::trace("Page loadRecursive()",'System.Web.UI.TPage');
+ $this->loadRecursive();
+
+ Prado::trace("Page processPostData()",'System.Web.UI.TPage');
+ $this->processPostData($this->_restPostData,false);
+
+ Prado::trace("Page raiseChangedEvents()",'System.Web.UI.TPage');
+ $this->raiseChangedEvents();
+
+
+ $this->getAdapter()->processCallbackEvent($writer);
+
+/*
+ Prado::trace("Page raisePostBackEvent()",'System.Web.UI.TPage');
+ $this->raisePostBackEvent();
+*/
+ Prado::trace("Page onLoadComplete()",'System.Web.UI.TPage');
+ $this->onLoadComplete(null);
+
+ Prado::trace("Page preRenderRecursive()",'System.Web.UI.TPage');
+ $this->preRenderRecursive();
+ Prado::trace("Page onPreRenderComplete()",'System.Web.UI.TPage');
+ $this->onPreRenderComplete(null);
+
+ Prado::trace("Page savePageState()",'System.Web.UI.TPage');
+ $this->savePageState();
+ Prado::trace("Page onSaveStateComplete()",'System.Web.UI.TPage');
+ $this->onSaveStateComplete(null);
+
+/*
+ Prado::trace("Page renderControl()",'System.Web.UI.TPage');
+ $this->renderControl($writer);
+*/
+ $this->getAdapter()->renderCallbackResponse($writer);
+
+ Prado::trace("Page unloadRecursive()",'System.Web.UI.TPage');
+ $this->unloadRecursive();
+ }
+
+ /**
+ * Gets the callback client script handler that allows javascript functions
+ * to be executed during the callback response.
+ * @return TCallbackClientScript interface to client-side javascript code.
+ */
+ public function getCallbackClient()
+ {
+ if($this->getAdapter() !== null)
+ return $this->getAdapter()->getCallbackClientHandler();
+ else
+ return new TCallbackClientScript();
+ }
+
+ /**
+ * Set a new callback client handler.
+ * @param TCallbackClientScript new callback client script handler.
+ */
+ public function setCallbackClient($client)
+ {
+ $this->getAdapter()->setCallbackClientHandler($client);
+ }
+
+ /**
+ * @return TControl the control responsible for the current callback event,
+ * null if nonexistent
+ */
+ public function getCallbackEventTarget()
+ {
+ return $this->getAdapter()->getCallbackEventTarget();
+ }
+
+ /**
+ * Registers a control to raise callback event in the current request.
+ * @param TControl control registered to raise callback event.
+ */
+ public function setCallbackEventTarget(TControl $control)
+ {
+ $this->getAdapter()->setCallbackEventTarget($control);
+ }
+
+ /**
+ * Callback parameter is decoded assuming JSON encoding.
+ * @return string callback event parameter
+ */
+ public function getCallbackEventParameter()
+ {
+ return $this->getAdapter()->getCallbackEventParameter();
+ }
+
+ /**
+ * @param mixed callback event parameter
+ */
+ public function setCallbackEventParameter($value)
+ {
+ $this->getAdapter()->setCallbackEventParameter($value);
+ }
+
+ /**
+ * Register post data loaders for Callback to collect post data.
+ * This method should only be called by framework developers.
+ * @param TControl control that requires post data.
+ * @see TControl::preRenderRecursive();
+ */
+ public function registerPostDataLoader($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_postDataLoaders[$id] = true;
+ }
+
+ /**
+ * Get a list of IDs of controls that are enabled and require post data.
+ * @return array list of IDs implementing IPostBackDataHandler
+ */
+ public function getPostDataLoaders()
+ {
+ return array_keys($this->_postDataLoaders);
+ }
+
+ /**
+ * @return TForm the form on the page
+ */
+ public function getForm()
+ {
+ return $this->_form;
+ }
+
+ /**
+ * Registers a TForm instance to the page.
+ * Note, a page can contain at most one TForm instance.
+ * @param TForm the form on the page
+ * @throws TInvalidOperationException if this method is invoked twice or more.
+ */
+ public function setForm(TForm $form)
+ {
+ if($this->_form===null)
+ $this->_form=$form;
+ else
+ throw new TInvalidOperationException('page_form_duplicated');
+ }
+
+ /**
+ * Returns a list of registered validators.
+ * If validation group is specified, only the validators in that group will be returned.
+ * @param string validation group
+ * @return TList registered validators in the requested group. If the group is null, all validators will be returned.
+ */
+ public function getValidators($validationGroup=null)
+ {
+ if(!$this->_validators)
+ $this->_validators=new TList;
+ if(empty($validationGroup) === true)
+ return $this->_validators;
+ else
+ {
+ $list=new TList;
+ foreach($this->_validators as $validator)
+ if($validator->getValidationGroup()===$validationGroup)
+ $list->add($validator);
+ return $list;
+ }
+ }
+
+ /**
+ * Performs input validation.
+ * This method will invoke the registered validators to perform the actual validation.
+ * If validation group is specified, only the validators in that group will be invoked.
+ * @param string validation group. If null, all validators will perform validation.
+ */
+ public function validate($validationGroup=null)
+ {
+ Prado::trace("Page validate()",'System.Web.UI.TPage');
+ $this->_validated=true;
+ if($this->_validators && $this->_validators->getCount())
+ {
+ if($validationGroup===null)
+ {
+ foreach($this->_validators as $validator)
+ $validator->validate();
+ }
+ else
+ {
+ foreach($this->_validators as $validator)
+ {
+ if($validator->getValidationGroup()===$validationGroup)
+ $validator->validate();
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns whether user input is valid or not.
+ * This method must be invoked after {@link validate} is called.
+ * @return boolean whether the user input is valid or not.
+ * @throws TInvalidOperationException if {@link validate} is not invoked yet.
+ */
+ public function getIsValid()
+ {
+ if($this->_validated)
+ {
+ if($this->_validators && $this->_validators->getCount())
+ {
+ foreach($this->_validators as $validator)
+ if(!$validator->getIsValid())
+ return false;
+ }
+ return true;
+ }
+ else
+ throw new TInvalidOperationException('page_isvalid_unknown');
+ }
+
+ /**
+ * @return TTheme the theme used for the page. Defaults to null.
+ */
+ public function getTheme()
+ {
+ if(is_string($this->_theme))
+ $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme);
+ return $this->_theme;
+ }
+
+ /**
+ * Sets the theme to be used for the page.
+ * @param string|TTheme the theme name or the theme object to be used for the page.
+ */
+ public function setTheme($value)
+ {
+ $this->_theme=empty($value)?null:$value;
+ }
+
+
+ /**
+ * @return TTheme the stylesheet theme used for the page. Defaults to null.
+ */
+ public function getStyleSheetTheme()
+ {
+ if(is_string($this->_styleSheet))
+ $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet);
+ return $this->_styleSheet;
+ }
+
+ /**
+ * Sets the stylesheet theme to be used for the page.
+ * @param string|TTheme the stylesheet theme name or the stylesheet theme object to be used for the page.
+ */
+ public function setStyleSheetTheme($value)
+ {
+ $this->_styleSheet=empty($value)?null:$value;
+ }
+
+ /**
+ * Applies a skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied skin with
+ */
+ public function applyControlSkin($control)
+ {
+ if(($theme=$this->getTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * Applies a stylesheet skin in the current theme to a control.
+ * This method should only be used by framework developers.
+ * @param TControl a control to be applied stylesheet skin with
+ */
+ public function applyControlStyleSheet($control)
+ {
+ if(($theme=$this->getStyleSheetTheme())!==null)
+ $theme->applySkin($control);
+ }
+
+ /**
+ * @return TClientScriptManager client script manager
+ */
+ public function getClientScript()
+ {
+ if(!$this->_clientScript) {
+ $className = $classPath = $this->getService()->getClientScriptManagerClass();
+ Prado::using($className);
+ if(($pos=strrpos($className,'.'))!==false)
+ $className=substr($className,$pos+1);
+
+ if(!class_exists($className,false) || ($className!=='TClientScriptManager' && !is_subclass_of($className,'TClientScriptManager')))
+ throw new THttpException(404,'page_csmanagerclass_invalid',$classPath);
+
+ $this->_clientScript=new $className($this);
+ }
+ return $this->_clientScript;
+ }
+
+ /**
+ * Raises OnPreInit event.
+ * This method is invoked right before {@link onInit OnInit} stage.
+ * You may override this method to provide additional initialization that
+ * should be done before {@link onInit OnInit} (e.g. setting {@link setTheme Theme} or
+ * {@link setStyleSheetTheme StyleSheetTheme}).
+ * Remember to call the parent implementation to ensure OnPreInit event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreInit($param)
+ {
+ $this->raiseEvent('OnPreInit',$this,$param);
+ }
+
+ /**
+ * Raises OnInitComplete event.
+ * This method is invoked right after {@link onInit OnInit} stage and before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional initialization that
+ * should be done after {@link onInit OnInit}.
+ * Remember to call the parent implementation to ensure OnInitComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onInitComplete($param)
+ {
+ $this->raiseEvent('OnInitComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreLoad event.
+ * This method is invoked right before {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done before {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnPreLoad event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreLoad($param)
+ {
+ $this->raiseEvent('OnPreLoad',$this,$param);
+ }
+
+ /**
+ * Raises OnLoadComplete event.
+ * This method is invoked right after {@link onLoad OnLoad} stage.
+ * You may override this method to provide additional page loading logic that
+ * should be done after {@link onLoad OnLoad}.
+ * Remember to call the parent implementation to ensure OnLoadComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onLoadComplete($param)
+ {
+ $this->raiseEvent('OnLoadComplete',$this,$param);
+ }
+
+ /**
+ * Raises OnPreRenderComplete event.
+ * This method is invoked right after {@link onPreRender OnPreRender} stage.
+ * You may override this method to provide additional preparation for page rendering
+ * that should be done after {@link onPreRender OnPreRender}.
+ * Remember to call the parent implementation to ensure OnPreRenderComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onPreRenderComplete($param)
+ {
+ $this->raiseEvent('OnPreRenderComplete',$this,$param);
+ $cs=$this->getClientScript();
+ $theme=$this->getTheme();
+ if($theme instanceof ITheme)
+ {
+ foreach($theme->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($theme->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+ $styleSheet=$this->getStyleSheetTheme();
+ if($styleSheet instanceof ITheme)
+ {
+ foreach($styleSheet->getStyleSheetFiles() as $url)
+ $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url));
+ foreach($styleSheet->getJavaScriptFiles() as $url)
+ $cs->registerHeadScriptFile($url,$url);
+ }
+
+ if($cs->getRequiresHead() && $this->getHead()===null)
+ throw new TConfigurationException('page_head_required');
+ }
+
+ /**
+ * Determines the media type of the CSS file.
+ * The media type is determined according to the following file name pattern:
+ * xxx.media-type.extension
+ * For example, 'mystyle.print.css' means its media type is 'print'.
+ * @param string CSS URL
+ * @return string media type of the CSS file
+ */
+ private function getCssMediaType($url)
+ {
+ $segs=explode('.',basename($url));
+ if(isset($segs[2]))
+ return $segs[count($segs)-2];
+ else
+ return '';
+ }
+
+ /**
+ * Raises OnSaveStateComplete event.
+ * This method is invoked right after {@link onSaveState OnSaveState} stage.
+ * You may override this method to provide additional logic after page state is saved.
+ * Remember to call the parent implementation to ensure OnSaveStateComplete event is raised.
+ * @param mixed event parameter
+ */
+ public function onSaveStateComplete($param)
+ {
+ $this->raiseEvent('OnSaveStateComplete',$this,$param);
+ }
+
+ /**
+ * Determines whether the current page request is a postback.
+ * Call {@link getIsPostBack} to get the result.
+ */
+ private function determinePostBackMode()
+ {
+ $postData=$this->getRequest();
+ if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET))
+ $this->_postData=$postData;
+ }
+
+ /**
+ * @return boolean whether the current page request is a postback
+ */
+ public function getIsPostBack()
+ {
+ return $this->_postData!==null;
+ }
+
+ /**
+ * @return boolean whether this is a callback request
+ */
+ public function getIsCallback()
+ {
+ return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET);
+ }
+
+ /**
+ * This method is invoked when control state is to be saved.
+ * You can override this method to do last step state saving.
+ * Parent implementation must be invoked.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array());
+ }
+
+ /**
+ * This method is invoked right after the control has loaded its state.
+ * You can override this method to initialize data from the control state.
+ * Parent implementation must be invoked.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array());
+ }
+
+ /**
+ * Loads page state from persistent storage.
+ */
+ protected function loadPageState()
+ {
+ Prado::trace("Loading state",'System.Web.UI.TPage');
+ $state=$this->getStatePersister()->load();
+ $this->loadStateRecursive($state,$this->getEnableViewState());
+ }
+
+ /**
+ * Saves page state from persistent storage.
+ */
+ protected function savePageState()
+ {
+ Prado::trace("Saving state",'System.Web.UI.TPage');
+ $state=&$this->saveStateRecursive($this->getEnableViewState());
+ $this->getStatePersister()->save($state);
+ }
+
+ /**
+ * @param string the field name
+ * @return boolean whether the specified field is a system field in postback data
+ */
+ protected function isSystemPostField($field)
+ {
+ return isset(self::$_systemPostFields[$field]);
+ }
+
+ /**
+ * Registers a control for loading post data in the next postback.
+ * This method needs to be invoked if the control to load post data
+ * may not have a post variable in some cases. For example, a checkbox,
+ * if not checked, will not have a post value.
+ * @param TControl control registered for loading post data
+ */
+ public function registerRequiresPostData($control)
+ {
+ $id=is_string($control)?$control:$control->getUniqueID();
+ $this->_controlsRegisteredForPostData[$id]=true;
+ $this->registerPostDataLoader($id);
+ $params=func_get_args();
+ foreach($this->getCachingStack() as $item)
+ $item->registerAction('Page','registerRequiresPostData',array($id));
+ }
+
+ /**
+ * @return TControl the control responsible for the current postback event, null if nonexistent
+ */
+ public function getPostBackEventTarget()
+ {
+ if($this->_postBackEventTarget===null && $this->_postData!==null)
+ {
+ $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET);
+ if(!empty($eventTarget))
+ $this->_postBackEventTarget=$this->findControl($eventTarget);
+ }
+ return $this->_postBackEventTarget;
+ }
+
+ /**
+ * Registers a control to raise postback event in the current request.
+ * @param TControl control registered to raise postback event.
+ */
+ public function setPostBackEventTarget(TControl $control)
+ {
+ $this->_postBackEventTarget=$control;
+ }
+
+ /**
+ * @return string postback event parameter
+ */
+ public function getPostBackEventParameter()
+ {
+ if($this->_postBackEventParameter===null && $this->_postData!==null)
+ {
+ if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null)
+ $this->_postBackEventParameter='';
+ }
+ return $this->_postBackEventParameter;
+ }
+
+ /**
+ * @param string postback event parameter
+ */
+ public function setPostBackEventParameter($value)
+ {
+ $this->_postBackEventParameter=$value;
+ }
+
+ /**
+ * Processes post data.
+ * @param TMap post data to be processed
+ * @param boolean whether this method is invoked before {@link onLoad OnLoad}.
+ */
+ protected function processPostData($postData,$beforeLoad)
+ {
+ $this->_isLoadingPostData=true;
+ if($beforeLoad)
+ $this->_restPostData=new TMap;
+ foreach($postData as $key=>$value)
+ {
+ if($this->isSystemPostField($key))
+ continue;
+ else if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else if($control instanceof IPostBackEventHandler &&
+ empty($this->_postData[self::FIELD_POSTBACK_TARGET]))
+ {
+ $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); // not calling setPostBackEventTarget() because the control may be removed later
+ }
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ else if($beforeLoad)
+ $this->_restPostData->add($key,$value);
+ }
+
+ foreach($this->_controlsRequiringPostData as $key=>$value)
+ {
+ if($control=$this->findControl($key))
+ {
+ if($control instanceof IPostBackDataHandler)
+ {
+ if($control->loadPostData($key,$this->_postData))
+ $this->_controlsPostDataChanged[]=$control;
+ }
+ else
+ throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key);
+ unset($this->_controlsRequiringPostData[$key]);
+ }
+ }
+ $this->_isLoadingPostData=false;
+ }
+
+ /**
+ * @return boolean true if loading post data.
+ */
+ public function getIsLoadingPostData()
+ {
+ return $this->_isLoadingPostData;
+ }
+
+ /**
+ * Raises OnPostDataChangedEvent for controls whose data have been changed due to the postback.
+ */
+ protected function raiseChangedEvents()
+ {
+ foreach($this->_controlsPostDataChanged as $control)
+ $control->raisePostDataChangedEvent();
+ }
+
+ /**
+ * Raises PostBack event.
+ */
+ protected function raisePostBackEvent()
+ {
+ if(($postBackHandler=$this->getPostBackEventTarget())===null)
+ $this->validate();
+ else if($postBackHandler instanceof IPostBackEventHandler)
+ $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter());
+ }
+
+ /**
+ * @return boolean Whether form rendering is in progress
+ */
+ public function getInFormRender()
+ {
+ return $this->_inFormRender;
+ }
+
+ /**
+ * Ensures the control is rendered within a form.
+ * @param TControl the control to be rendered
+ * @throws TConfigurationException if the control is outside of the form
+ */
+ public function ensureRenderInForm($control)
+ {
+ if(!$this->getIsCallback() && !$this->_inFormRender)
+ throw new TConfigurationException('page_control_outofform',get_class($control), $control ? $control->getUniqueID() : null);
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the beginning of its rendering
+ */
+ public function beginFormRender($writer)
+ {
+ if($this->_formRendered)
+ throw new TConfigurationException('page_form_duplicated');
+ $this->_formRendered=true;
+ $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState());
+ $this->_inFormRender=true;
+ }
+
+ /**
+ * @internal This method is invoked by TForm at the end of its rendering
+ */
+ public function endFormRender($writer)
+ {
+ if($this->_focus)
+ {
+ if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true))
+ $focus=$this->_focus->getClientID();
+ else
+ $focus=$this->_focus;
+ $this->getClientScript()->registerFocusControl($focus);
+ }
+ else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null)
+ $this->getClientScript()->registerFocusControl($lastFocus);
+ $this->_inFormRender=false;
+ }
+
+ /**
+ * Sets input focus on a control after the page is rendered to users.
+ * @param TControl|string control to receive focus, or the ID of the element on the page to receive focus
+ */
+ public function setFocus($value)
+ {
+ $this->_focus=$value;
+ }
+
+ /**
+ * @return boolean whether client supports javascript. Defaults to true.
+ */
+ public function getClientSupportsJavaScript()
+ {
+ return $this->_enableJavaScript;
+ }
+
+ /**
+ * @param boolean whether client supports javascript. If false, javascript will not be generated for controls.
+ */
+ public function setClientSupportsJavaScript($value)
+ {
+ $this->_enableJavaScript=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THead page head, null if not available
+ */
+ public function getHead()
+ {
+ return $this->_head;
+ }
+
+ /**
+ * @param THead page head
+ * @throws TInvalidOperationException if a head already exists
+ */
+ public function setHead(THead $value)
+ {
+ if($this->_head)
+ throw new TInvalidOperationException('page_head_duplicated');
+ $this->_head=$value;
+ if($this->_title!==null)
+ {
+ $this->_head->setTitle($this->_title);
+ $this->_title=null;
+ }
+ }
+
+ /**
+ * @return string page title.
+ */
+ public function getTitle()
+ {
+ if($this->_head)
+ return $this->_head->getTitle();
+ else
+ return $this->_title===null ? '' : $this->_title;
+ }
+
+ /**
+ * Sets the page title.
+ * Note, a {@link THead} control needs to place on the page
+ * in order that this title be rendered.
+ * @param string page title. This will override the title set in {@link getHead Head}.
+ */
+ public function setTitle($value)
+ {
+ if($this->_head)
+ $this->_head->setTitle($value);
+ else
+ $this->_title=$value;
+ }
+
+ /**
+ * Returns the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @return string the state to be stored on the client side
+ */
+ public function getClientState()
+ {
+ return $this->_clientState;
+ }
+
+ /**
+ * Sets the state to be stored on the client side.
+ * This method should only be used by framework and control developers.
+ * @param string the state to be stored on the client side
+ */
+ public function setClientState($state)
+ {
+ $this->_clientState=$state;
+ }
+
+ /**
+ * @return string the state postback from client side
+ */
+ public function getRequestClientState()
+ {
+ return $this->getRequest()->itemAt(self::FIELD_PAGESTATE);
+ }
+
+ /**
+ * @return string class name of the page state persister. Defaults to TPageStatePersister.
+ */
+ public function getStatePersisterClass()
+ {
+ return $this->_statePersisterClass;
+ }
+
+ /**
+ * @param string class name of the page state persister.
+ */
+ public function setStatePersisterClass($value)
+ {
+ $this->_statePersisterClass=$value;
+ }
+
+ /**
+ * @return IPageStatePersister page state persister
+ */
+ public function getStatePersister()
+ {
+ if($this->_statePersister===null)
+ {
+ $this->_statePersister=Prado::createComponent($this->_statePersisterClass);
+ if(!($this->_statePersister instanceof IPageStatePersister))
+ throw new TInvalidDataTypeException('page_statepersister_invalid');
+ $this->_statePersister->setPage($this);
+ }
+ return $this->_statePersister;
+ }
+
+ /**
+ * @return boolean whether page state should be HMAC validated. Defaults to true.
+ */
+ public function getEnableStateValidation()
+ {
+ return $this->_enableStateValidation;
+ }
+
+ /**
+ * @param boolean whether page state should be HMAC validated.
+ */
+ public function setEnableStateValidation($value)
+ {
+ $this->_enableStateValidation=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be encrypted. Defaults to false.
+ */
+ public function getEnableStateEncryption()
+ {
+ return $this->_enableStateEncryption;
+ }
+
+ /**
+ * @param boolean whether page state should be encrypted.
+ */
+ public function setEnableStateEncryption($value)
+ {
+ $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether page state should be compressed. Defaults to true.
+ * @since 3.1.6
+ */
+ public function getEnableStateCompression()
+ {
+ return $this->_enableStateCompression;
+ }
+
+ /**
+ * @param boolean whether page state should be compressed.
+ * @since 3.1.6
+ */
+ public function setEnableStateCompression($value)
+ {
+ $this->_enableStateCompression=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string the requested page path for this page
+ */
+ public function getPagePath()
+ {
+ return $this->_pagePath;
+ }
+
+ /**
+ * @param string the requested page path for this page
+ */
+ public function setPagePath($value)
+ {
+ $this->_pagePath=$value;
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript).
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerCachingAction($context,$funcName,$funcParams)
+ {
+ if($this->_cachingStack)
+ {
+ foreach($this->_cachingStack as $cache)
+ $cache->registerAction($context,$funcName,$funcParams);
+ }
+ }
+
+ /**
+ * @return TStack stack of {@link TOutputCache} objects
+ */
+ public function getCachingStack()
+ {
+ if(!$this->_cachingStack)
+ $this->_cachingStack=new TStack;
+ return $this->_cachingStack;
+ }
+
+ /**
+ * Flushes output
+ */
+ public function flushWriter()
+ {
+ if ($this->_writer)
+ $this->Response->write($this->_writer->flush());
+ }
+}
+
+/**
+ * IPageStatePersister interface.
+ *
+ * IPageStatePersister interface is required for all page state persister
+ * classes.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1
+ */
+interface IPageStatePersister
+{
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage();
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page);
+ /**
+ * Saves state to persistent storage.
+ * @param mixed state to be stored
+ */
+ public function save($state);
+ /**
+ * Loads page state from persistent storage
+ * @return mixed the restored state
+ */
+ public function load();
+}
+
+
+/**
+ * TPageStateFormatter class.
+ *
+ * TPageStateFormatter is a utility class to transform the page state
+ * into and from a string that can be properly saved in persistent storage.
+ *
+ * Depending on the {@link TPage::getEnableStateValidation() EnableStateValidation}
+ * and {@link TPage::getEnableStateEncryption() EnableStateEncryption},
+ * TPageStateFormatter may do HMAC validation and encryption to prevent
+ * the state data from being tampered or viewed.
+ * The private keys and hashing/encryption methods are determined by
+ * {@link TApplication::getSecurityManager() SecurityManager}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Revision: $ $Date: $
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TPageStateFormatter
+{
+ /**
+ * @param TPage
+ * @param mixed state data
+ * @return string serialized data
+ */
+ public static function serialize($page,$data)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateValidation())
+ $str=$sm->hashData(Prado::serialize($data));
+ else
+ $str=Prado::serialize($data);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=gzcompress($str);
+ if($page->getEnableStateEncryption())
+ $str=$sm->encrypt($str);
+ return base64_encode($str);
+ }
+
+ /**
+ * @param TPage
+ * @param string serialized data
+ * @return mixed unserialized state data, null if data is corrupted
+ */
+ public static function unserialize($page,$data)
+ {
+ $str=base64_decode($data);
+ if($str==='')
+ return null;
+ if($str!==false)
+ {
+ $sm=$page->getApplication()->getSecurityManager();
+ if($page->getEnableStateEncryption())
+ $str=$sm->decrypt($str);
+ if($page->getEnableStateCompression() && extension_loaded('zlib'))
+ $str=@gzuncompress($str);
+ if($page->getEnableStateValidation())
+ {
+ if(($str=$sm->validateData($str))!==false)
+ return Prado::unserialize($str);
+ }
+ else
+ return Prado::unserialize($str);
+ }
+ return null;
+ }
+}
diff --git a/framework/Web/UI/TPageStatePersister.php b/framework/Web/UI/TPageStatePersister.php
index 18590a77..183cde13 100644
--- a/framework/Web/UI/TPageStatePersister.php
+++ b/framework/Web/UI/TPageStatePersister.php
@@ -1,71 +1,71 @@
-<?php
-/**
- * TPageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TPageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TPageStatePersister class
- *
- * TPageStatePersister implements a page state persistent method based on
- * form hidden fields.
- *
- * Since page state can be very big for complex pages, consider using
- * alternative persisters, such as {@link TSessionPageStatePersister},
- * which store page state on the server side and thus reduce the network
- * traffic for transmitting bulky page state.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TPageStatePersister extends TComponent implements IPageStatePersister
-{
- private $_page;
-
- /**
- * @return TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * Saves state in hidden fields.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
- }
-
- /**
- * Loads page state from hidden fields.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- return $data;
- else
- throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TPageStatePersister class
+ *
+ * TPageStatePersister implements a page state persistent method based on
+ * form hidden fields.
+ *
+ * Since page state can be very big for complex pages, consider using
+ * alternative persisters, such as {@link TSessionPageStatePersister},
+ * which store page state on the server side and thus reduce the network
+ * traffic for transmitting bulky page state.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TPageStatePersister extends TComponent implements IPageStatePersister
+{
+ private $_page;
+
+ /**
+ * @return TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * Saves state in hidden fields.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$state));
+ }
+
+ /**
+ * Loads page state from hidden fields.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($data=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ return $data;
+ else
+ throw new THttpException(400,'pagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TSessionPageStatePersister.php b/framework/Web/UI/TSessionPageStatePersister.php
index 4c2537df..a6d26f7a 100644
--- a/framework/Web/UI/TSessionPageStatePersister.php
+++ b/framework/Web/UI/TSessionPageStatePersister.php
@@ -1,131 +1,131 @@
-<?php
-/**
- * TSessionPageStatePersister class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TSessionPageStatePersister class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * TSessionPageStatePersister class
- *
- * TSessionPageStatePersister implements a page state persistent method based on
- * sessions. Page state are stored in user sessions and therefore, this persister
- * requires session to be started and available.
- *
- * TSessionPageStatePersister keeps limited number of history states in session,
- * mainly to preserve the precious server storage. The number is specified
- * by {@link setHistorySize HistorySize}, which defaults to 10.
- *
- * There are a couple of ways to use TSessionPageStatePersister.
- * One can override the page's {@link TPage::getStatePersister()} method and
- * create a TSessionPageStatePersister instance there.
- * Or one can configure the pages to use TSessionPageStatePersister in page configurations
- * as follows,
- * <code>
- * <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
- * </code>
- * The above configuration will affect the pages under the directory containing
- * this configuration and all its subdirectories.
- * To configure individual pages to use TSessionPageStatePersister, use
- * <code>
- * <pages>
- * <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
- * </pages>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.1
- */
-class TSessionPageStatePersister extends TComponent implements IPageStatePersister
-{
- const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
- const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
-
- private $_page;
- private $_historySize=10;
-
- /**
- * @param TPage the page that this persister works for
- */
- public function getPage()
- {
- return $this->_page;
- }
-
- /**
- * @param TPage the page that this persister works for.
- */
- public function setPage(TPage $page)
- {
- $this->_page=$page;
- }
-
- /**
- * @return integer maximum number of page states that should be kept in session. Defaults to 10.
- */
- public function getHistorySize()
- {
- return $this->_historySize;
- }
-
- /**
- * @param integer maximum number of page states that should be kept in session
- * @throws TInvalidDataValueException if the number is smaller than 1.
- */
- public function setHistorySize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))>0)
- $this->_historySize=$value;
- else
- throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
- }
- /**
- * Saves state in session.
- * @param mixed state to be stored
- */
- public function save($state)
- {
- $session=$this->_page->getSession();
- $session->open();
- $data=serialize($state);
- $timestamp=(string)microtime(true);
- $key=self::STATE_SESSION_KEY.$timestamp;
- $session->add($key,$data);
- if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
- $queue=array();
- $queue[]=$key;
- if(count($queue)>$this->getHistorySize())
- {
- $expiredKey=array_shift($queue);
- $session->remove($expiredKey);
- }
- $session->add(self::QUEUE_SESSION_KEY,$queue);
- $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
- }
-
- /**
- * Loads page state from session.
- * @return mixed the restored state
- * @throws THttpException if page state is corrupted
- */
- public function load()
- {
- if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
- {
- $session=$this->_page->getSession();
- $session->open();
- $key=self::STATE_SESSION_KEY.$timestamp;
- if(($data=$session->itemAt($key))!==null)
- return unserialize($data);
- }
- throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * TSessionPageStatePersister class
+ *
+ * TSessionPageStatePersister implements a page state persistent method based on
+ * sessions. Page state are stored in user sessions and therefore, this persister
+ * requires session to be started and available.
+ *
+ * TSessionPageStatePersister keeps limited number of history states in session,
+ * mainly to preserve the precious server storage. The number is specified
+ * by {@link setHistorySize HistorySize}, which defaults to 10.
+ *
+ * There are a couple of ways to use TSessionPageStatePersister.
+ * One can override the page's {@link TPage::getStatePersister()} method and
+ * create a TSessionPageStatePersister instance there.
+ * Or one can configure the pages to use TSessionPageStatePersister in page configurations
+ * as follows,
+ * <code>
+ * <pages StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
+ * </code>
+ * The above configuration will affect the pages under the directory containing
+ * this configuration and all its subdirectories.
+ * To configure individual pages to use TSessionPageStatePersister, use
+ * <code>
+ * <pages>
+ * <page id="PageID" StatePersisterClass="System.Web.UI.TSessionPageStatePersister" />
+ * </pages>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.1
+ */
+class TSessionPageStatePersister extends TComponent implements IPageStatePersister
+{
+ const STATE_SESSION_KEY='PRADO_SESSION_PAGESTATE';
+ const QUEUE_SESSION_KEY='PRADO_SESSION_STATEQUEUE';
+
+ private $_page;
+ private $_historySize=10;
+
+ /**
+ * @param TPage the page that this persister works for
+ */
+ public function getPage()
+ {
+ return $this->_page;
+ }
+
+ /**
+ * @param TPage the page that this persister works for.
+ */
+ public function setPage(TPage $page)
+ {
+ $this->_page=$page;
+ }
+
+ /**
+ * @return integer maximum number of page states that should be kept in session. Defaults to 10.
+ */
+ public function getHistorySize()
+ {
+ return $this->_historySize;
+ }
+
+ /**
+ * @param integer maximum number of page states that should be kept in session
+ * @throws TInvalidDataValueException if the number is smaller than 1.
+ */
+ public function setHistorySize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))>0)
+ $this->_historySize=$value;
+ else
+ throw new TInvalidDataValueException('sessionpagestatepersister_historysize_invalid');
+ }
+ /**
+ * Saves state in session.
+ * @param mixed state to be stored
+ */
+ public function save($state)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $data=serialize($state);
+ $timestamp=(string)microtime(true);
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ $session->add($key,$data);
+ if(($queue=$session->itemAt(self::QUEUE_SESSION_KEY))===null)
+ $queue=array();
+ $queue[]=$key;
+ if(count($queue)>$this->getHistorySize())
+ {
+ $expiredKey=array_shift($queue);
+ $session->remove($expiredKey);
+ }
+ $session->add(self::QUEUE_SESSION_KEY,$queue);
+ $this->_page->setClientState(TPageStateFormatter::serialize($this->_page,$timestamp));
+ }
+
+ /**
+ * Loads page state from session.
+ * @return mixed the restored state
+ * @throws THttpException if page state is corrupted
+ */
+ public function load()
+ {
+ if(($timestamp=TPageStateFormatter::unserialize($this->_page,$this->_page->getRequestClientState()))!==null)
+ {
+ $session=$this->_page->getSession();
+ $session->open();
+ $key=self::STATE_SESSION_KEY.$timestamp;
+ if(($data=$session->itemAt($key))!==null)
+ return unserialize($data);
+ }
+ throw new THttpException(400,'sessionpagestatepersister_pagestate_corrupted');
+ }
+}
+
diff --git a/framework/Web/UI/TTemplateControl.php b/framework/Web/UI/TTemplateControl.php
index 400c1059..9b26728d 100644
--- a/framework/Web/UI/TTemplateControl.php
+++ b/framework/Web/UI/TTemplateControl.php
@@ -1,243 +1,243 @@
-<?php
-/**
- * TTemplateControl class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTemplateControl class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TCompositeControl class
- */
-Prado::using('System.Web.UI.TCompositeControl');
-
-/**
- * TTemplateControl class.
- * TTemplateControl is the base class for all controls that use templates.
- * By default, a control template is assumed to be in a file under the same
- * directory with the control class file. They have the same file name and
- * different extension name. For template file, the extension name is ".tpl".
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateControl extends TCompositeControl
-{
- /**
- * template file extension.
- */
- const EXT_TEMPLATE='.tpl';
-
- /**
- * @var ITemplate the parsed template structure shared by the same control class
- */
- private static $_template=array();
- /**
- * @var ITemplate the parsed template structure specific for this control instance
- */
- private $_localTemplate=null;
- /**
- * @var TTemplateControl the master control if any
- */
- private $_master=null;
- /**
- * @var string master control class name
- */
- private $_masterClass='';
- /**
- * @var array list of TContent controls
- */
- private $_contents=array();
- /**
- * @var array list of TContentPlaceHolder controls
- */
- private $_placeholders=array();
-
- /**
- * Returns the template object associated with this control object.
- * @return ITemplate|null the parsed template, null if none
- */
- public function getTemplate()
- {
- if($this->_localTemplate===null)
- {
- $class=get_class($this);
- if(!isset(self::$_template[$class]))
- self::$_template[$class]=$this->loadTemplate();
- return self::$_template[$class];
- }
- else
- return $this->_localTemplate;
- }
-
- /**
- * Sets the parsed template.
- * Note, the template will be applied to the whole control class.
- * This method should only be used by framework and control developers.
- * @param ITemplate the parsed template
- */
- public function setTemplate($value)
- {
- $this->_localTemplate=$value;
- }
-
- /**
- * @return boolean whether this control is a source template control.
- * A source template control loads its template from external storage,
- * such as file, db, rather than from within another template.
- */
- public function getIsSourceTemplateControl()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getIsSourceTemplate();
- else
- return false;
- }
-
- /**
- * @return string the directory containing the template. Empty if no template available.
- */
- public function getTemplateDirectory()
- {
- if(($template=$this->getTemplate())!==null)
- return $template->getContextPath();
- else
- return '';
- }
-
- /**
- * Loads the template associated with this control class.
- * @return ITemplate the parsed template structure
- */
- protected function loadTemplate()
- {
- Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
- $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
- return $template;
- }
-
- /**
- * Creates child controls.
- * This method is overridden to load and instantiate control template.
- * This method should only be used by framework and control developers.
- */
- public function createChildControls()
- {
- if($tpl=$this->getTemplate())
- {
- foreach($tpl->getDirective() as $name=>$value)
- {
- if(is_string($value))
- $this->setSubProperty($name,$value);
- else
- throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
- }
- $tpl->instantiateIn($this);
- }
- }
-
- /**
- * Registers a content control.
- * @param string ID of the content
- * @param TContent
- */
- public function registerContent($id,TContent $object)
- {
- if(isset($this->_contents[$id]))
- throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
- else
- $this->_contents[$id]=$object;
- }
-
- /**
- * Registers a content placeholder to this template control.
- * This method should only be used by framework and control developers.
- * @param string placeholder ID
- * @param TContentPlaceHolder placeholder control
- */
- public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
- {
- if(isset($this->_placeholders[$id]))
- throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
- else
- $this->_placeholders[$id]=$object;
- }
-
- /**
- * @return string master class name (in namespace form)
- */
- public function getMasterClass()
- {
- return $this->_masterClass;
- }
-
- /**
- * @param string master control class name (in namespace form)
- */
- public function setMasterClass($value)
- {
- $this->_masterClass=$value;
- }
-
- /**
- * @return TTemplateControl|null master control associated with this control, null if none
- */
- public function getMaster()
- {
- return $this->_master;
- }
-
- /**
- * Injects all content controls (and their children) to the corresponding content placeholders.
- * This method should only be used by framework and control developers.
- * @param string ID of the content control
- * @param TContent the content to be injected
- */
- public function injectContent($id,$content)
- {
- if(isset($this->_placeholders[$id]))
- {
- $placeholder=$this->_placeholders[$id];
- $controls=$placeholder->getParent()->getControls();
- $loc=$controls->remove($placeholder);
- $controls->insertAt($loc,$content);
- }
- else
- throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
- }
-
- /**
- * Performs the OnInit step for the control and all its child controls.
- * This method overrides the parent implementation
- * by ensuring child controls are created first,
- * and if master class is set, master will be applied.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- $this->ensureChildControls();
- if($this->_masterClass!=='')
- {
- $master=Prado::createComponent($this->_masterClass);
- if(!($master instanceof TTemplateControl))
- throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
- $this->_master=$master;
- $this->getControls()->clear();
- $this->getControls()->add($master);
- $master->ensureChildControls();
- foreach($this->_contents as $id=>$content)
- $master->injectContent($id,$content);
- }
- else if(!empty($this->_contents))
- throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
- parent::initRecursive($namingContainer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TCompositeControl class
+ */
+Prado::using('System.Web.UI.TCompositeControl');
+
+/**
+ * TTemplateControl class.
+ * TTemplateControl is the base class for all controls that use templates.
+ * By default, a control template is assumed to be in a file under the same
+ * directory with the control class file. They have the same file name and
+ * different extension name. For template file, the extension name is ".tpl".
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateControl extends TCompositeControl
+{
+ /**
+ * template file extension.
+ */
+ const EXT_TEMPLATE='.tpl';
+
+ /**
+ * @var ITemplate the parsed template structure shared by the same control class
+ */
+ private static $_template=array();
+ /**
+ * @var ITemplate the parsed template structure specific for this control instance
+ */
+ private $_localTemplate=null;
+ /**
+ * @var TTemplateControl the master control if any
+ */
+ private $_master=null;
+ /**
+ * @var string master control class name
+ */
+ private $_masterClass='';
+ /**
+ * @var array list of TContent controls
+ */
+ private $_contents=array();
+ /**
+ * @var array list of TContentPlaceHolder controls
+ */
+ private $_placeholders=array();
+
+ /**
+ * Returns the template object associated with this control object.
+ * @return ITemplate|null the parsed template, null if none
+ */
+ public function getTemplate()
+ {
+ if($this->_localTemplate===null)
+ {
+ $class=get_class($this);
+ if(!isset(self::$_template[$class]))
+ self::$_template[$class]=$this->loadTemplate();
+ return self::$_template[$class];
+ }
+ else
+ return $this->_localTemplate;
+ }
+
+ /**
+ * Sets the parsed template.
+ * Note, the template will be applied to the whole control class.
+ * This method should only be used by framework and control developers.
+ * @param ITemplate the parsed template
+ */
+ public function setTemplate($value)
+ {
+ $this->_localTemplate=$value;
+ }
+
+ /**
+ * @return boolean whether this control is a source template control.
+ * A source template control loads its template from external storage,
+ * such as file, db, rather than from within another template.
+ */
+ public function getIsSourceTemplateControl()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getIsSourceTemplate();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the directory containing the template. Empty if no template available.
+ */
+ public function getTemplateDirectory()
+ {
+ if(($template=$this->getTemplate())!==null)
+ return $template->getContextPath();
+ else
+ return '';
+ }
+
+ /**
+ * Loads the template associated with this control class.
+ * @return ITemplate the parsed template structure
+ */
+ protected function loadTemplate()
+ {
+ Prado::trace("Loading template ".get_class($this),'System.Web.UI.TTemplateControl');
+ $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this));
+ return $template;
+ }
+
+ /**
+ * Creates child controls.
+ * This method is overridden to load and instantiate control template.
+ * This method should only be used by framework and control developers.
+ */
+ public function createChildControls()
+ {
+ if($tpl=$this->getTemplate())
+ {
+ foreach($tpl->getDirective() as $name=>$value)
+ {
+ if(is_string($value))
+ $this->setSubProperty($name,$value);
+ else
+ throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name);
+ }
+ $tpl->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Registers a content control.
+ * @param string ID of the content
+ * @param TContent
+ */
+ public function registerContent($id,TContent $object)
+ {
+ if(isset($this->_contents[$id]))
+ throw new TConfigurationException('templatecontrol_contentid_duplicated',$id);
+ else
+ $this->_contents[$id]=$object;
+ }
+
+ /**
+ * Registers a content placeholder to this template control.
+ * This method should only be used by framework and control developers.
+ * @param string placeholder ID
+ * @param TContentPlaceHolder placeholder control
+ */
+ public function registerContentPlaceHolder($id,TContentPlaceHolder $object)
+ {
+ if(isset($this->_placeholders[$id]))
+ throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id);
+ else
+ $this->_placeholders[$id]=$object;
+ }
+
+ /**
+ * @return string master class name (in namespace form)
+ */
+ public function getMasterClass()
+ {
+ return $this->_masterClass;
+ }
+
+ /**
+ * @param string master control class name (in namespace form)
+ */
+ public function setMasterClass($value)
+ {
+ $this->_masterClass=$value;
+ }
+
+ /**
+ * @return TTemplateControl|null master control associated with this control, null if none
+ */
+ public function getMaster()
+ {
+ return $this->_master;
+ }
+
+ /**
+ * Injects all content controls (and their children) to the corresponding content placeholders.
+ * This method should only be used by framework and control developers.
+ * @param string ID of the content control
+ * @param TContent the content to be injected
+ */
+ public function injectContent($id,$content)
+ {
+ if(isset($this->_placeholders[$id]))
+ {
+ $placeholder=$this->_placeholders[$id];
+ $controls=$placeholder->getParent()->getControls();
+ $loc=$controls->remove($placeholder);
+ $controls->insertAt($loc,$content);
+ }
+ else
+ throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id);
+ }
+
+ /**
+ * Performs the OnInit step for the control and all its child controls.
+ * This method overrides the parent implementation
+ * by ensuring child controls are created first,
+ * and if master class is set, master will be applied.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ $this->ensureChildControls();
+ if($this->_masterClass!=='')
+ {
+ $master=Prado::createComponent($this->_masterClass);
+ if(!($master instanceof TTemplateControl))
+ throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid');
+ $this->_master=$master;
+ $this->getControls()->clear();
+ $this->getControls()->add($master);
+ $master->ensureChildControls();
+ foreach($this->_contents as $id=>$content)
+ $master->injectContent($id,$content);
+ }
+ else if(!empty($this->_contents))
+ throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this));
+ parent::initRecursive($namingContainer);
+ }
+}
+
diff --git a/framework/Web/UI/TTemplateManager.php b/framework/Web/UI/TTemplateManager.php
index 4d17806b..f884cd65 100644
--- a/framework/Web/UI/TTemplateManager.php
+++ b/framework/Web/UI/TTemplateManager.php
@@ -1,1075 +1,1075 @@
-<?php
-/**
- * TTemplateManager and TTemplate class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * Includes TOutputCache class file
- */
-Prado::using('System.Web.UI.WebControls.TOutputCache');
-
-/**
- * TTemplateManager class
- *
- * TTemplateManager manages the loading and parsing of control templates.
- *
- * There are two ways of loading a template, either by the associated template
- * control class name, or the template file name.
- * The former is via calling {@link getTemplateByClassName}, which tries to
- * locate the corresponding template file under the directory containing
- * the class file. The name of the template file is the class name with
- * the extension '.tpl'. To load a template from a template file path,
- * call {@link getTemplateByFileName}.
- *
- * By default, TTemplateManager is registered with {@link TPageService} as the
- * template manager module that can be accessed via {@link TPageService::getTemplateManager()}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplateManager extends TModule
-{
- /**
- * Template file extension
- */
- const TEMPLATE_FILE_EXT='.tpl';
- /**
- * Prefix of the cache variable name for storing parsed templates
- */
- const TEMPLATE_CACHE_PREFIX='prado:template:';
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * It starts output buffer if it is enabled.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- $this->getService()->setTemplateManager($this);
- }
-
- /**
- * Loads the template corresponding to the specified class name.
- * @return ITemplate template for the class name, null if template doesn't exist.
- */
- public function getTemplateByClassName($className)
- {
- $class=new ReflectionClass($className);
- $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
- return $this->getTemplateByFileName($tplFile);
- }
-
- /**
- * Loads the template from the specified file.
- * @return ITemplate template parsed from the specified file, null if the file doesn't exist.
- */
- public function getTemplateByFileName($fileName)
- {
- if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
- {
- Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager');
- if(($cache=$this->getApplication()->getCache())===null)
- return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- else
- {
- $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
- if(is_array($array))
- {
- list($template,$timestamps)=$array;
- if($this->getApplication()->getMode()===TApplicationMode::Performance)
- return $template;
- $cacheValid=true;
- foreach($timestamps as $tplFile=>$timestamp)
- {
- if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
- {
- $cacheValid=false;
- break;
- }
- }
- if($cacheValid)
- return $template;
- }
- $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
- $includedFiles=$template->getIncludedFiles();
- $timestamps=array();
- $timestamps[$fileName]=filemtime($fileName);
- foreach($includedFiles as $includedFile)
- $timestamps[$includedFile]=filemtime($includedFile);
- $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
- return $template;
- }
- }
- else
- return null;
- }
-
- /**
- * Finds a localized template file.
- * @param string template file.
- * @return string|null a localized template file if found, null otherwise.
- */
- protected function getLocalizedTemplate($filename)
- {
- if(($app=$this->getApplication()->getGlobalization(false))===null)
- return is_file($filename)?$filename:null;
- foreach($app->getLocalizedResource($filename) as $file)
- {
- if(($file=realpath($file))!==false && is_file($file))
- return $file;
- }
- return null;
- }
-}
-
-/**
- * TTemplate implements PRADO template parsing logic.
- * A TTemplate object represents a parsed PRADO control template.
- * It can instantiate the template as child controls of a specified control.
- * The template format is like HTML, with the following special tags introduced,
- * - component tags: a component tag represents the configuration of a component.
- * The tag name is in the format of com:ComponentType, where ComponentType is the component
- * class name. Component tags must be well-formed. Attributes of the component tag
- * are treated as either property initial values, event handler attachment, or regular
- * tag attributes.
- * - property tags: property tags are used to set large block of attribute values.
- * The property tag name is in the format of <prop:AttributeName> where AttributeName
- * can be a property name, an event name or a regular tag attribute name.
- * - group subproperty tags: subproperties of a common property can be configured using
- * <prop:MainProperty SubProperty1="Value1" SubProperty2="Value2" .../>
- * - directive: directive specifies the property values for the template owner.
- * It is in the format of <%@ property name-value pairs %>;
- * - expressions: They are in the format of <%= PHP expression %> and <%% PHP statements %>
- * - comments: There are two kinds of comments, regular HTML comments and special template comments.
- * The former is in the format of <!-- comments -->, which will be treated as text strings.
- * The latter is in the format of <!-- comments --!>, which will be stripped out.
- *
- * Tags other than the above are not required to be well-formed.
- *
- * A TTemplate object represents a parsed PRADO template. To instantiate the template
- * for a particular control, call {@link instantiateIn($control)}, which
- * will create and intialize all components specified in the template and
- * set their parent as $control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTemplate extends TApplicationComponent implements ITemplate
-{
- /**
- * '<!--.*?--!>' - template comments
- * '<!--.*?-->' - HTML comments
- * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags
- * '<\/?prop:([\w\.]+)\s*>' - property tags
- * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives
- * '<%[%#~\/\\$=\\[](.*?)%>' - expressions
- * '<prop:([\w\.]+)((?:\s*[\w\.]+=\'.*?\'|\s*[\w\.]+=".*?"|\s*[\w\.]+=<%.*?%>)*)\s*\/>' - group subproperty tags
- */
- const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
-
- /**
- * Different configurations of component property/event/attribute
- */
- const CONFIG_DATABIND=0;
- const CONFIG_EXPRESSION=1;
- const CONFIG_ASSET=2;
- const CONFIG_PARAMETER=3;
- const CONFIG_LOCALIZATION=4;
- const CONFIG_TEMPLATE=5;
-
- /**
- * @var array list of component tags and strings
- */
- private $_tpl=array();
- /**
- * @var array list of directive settings
- */
- private $_directive=array();
- /**
- * @var string context path
- */
- private $_contextPath;
- /**
- * @var string template file path (if available)
- */
- private $_tplFile=null;
- /**
- * @var integer the line number that parsing starts from (internal use)
- */
- private $_startingLine=0;
- /**
- * @var string template content to be parsed
- */
- private $_content;
- /**
- * @var boolean whether this template is a source template
- */
- private $_sourceTemplate=true;
- /**
- * @var string hash code of the template
- */
- private $_hashCode='';
- private $_tplControl=null;
- private $_includedFiles=array();
- private $_includeAtLine=array();
- private $_includeLines=array();
-
-
- /**
- * Constructor.
- * The template will be parsed after construction.
- * @param string the template string
- * @param string the template context directory
- * @param string the template file, null if no file
- * @param integer the line number that parsing starts from (internal use)
- * @param boolean whether this template is a source template, i.e., this template is loaded from
- * some external storage rather than from within another template.
- */
- public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
- {
- $this->_sourceTemplate=$sourceTemplate;
- $this->_contextPath=$contextPath;
- $this->_tplFile=$tplFile;
- $this->_startingLine=$startingLine;
- $this->_content=$template;
- $this->_hashCode=md5($template);
- $this->parse($template);
- $this->_content=null; // reset to save memory
- }
-
- /**
- * @return string template file path if available, null otherwise.
- */
- public function getTemplateFile()
- {
- return $this->_tplFile;
- }
-
- /**
- * @return boolean whether this template is a source template, i.e., this template is loaded from
- * some external storage rather than from within another template.
- */
- public function getIsSourceTemplate()
- {
- return $this->_sourceTemplate;
- }
-
- /**
- * @return string context directory path
- */
- public function getContextPath()
- {
- return $this->_contextPath;
- }
-
- /**
- * @return array name-value pairs declared in the directive
- */
- public function getDirective()
- {
- return $this->_directive;
- }
-
- /**
- * @return string hash code that can be used to identify the template
- */
- public function getHashCode()
- {
- return $this->_hashCode;
- }
-
- /**
- * @return array the parsed template
- */
- public function &getItems()
- {
- return $this->_tpl;
- }
-
- /**
- * Instantiates the template.
- * Content in the template will be instantiated as components and text strings
- * and passed to the specified parent control.
- * @param TControl the control who owns the template
- * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control.
- */
- public function instantiateIn($tplControl,$parentControl=null)
- {
- $this->_tplControl=$tplControl;
- if($parentControl===null)
- $parentControl=$tplControl;
- if(($page=$tplControl->getPage())===null)
- $page=$this->getService()->getRequestedPage();
- $controls=array();
- $directChildren=array();
- foreach($this->_tpl as $key=>$object)
- {
- if($object[0]===-1)
- $parent=$parentControl;
- else if(isset($controls[$object[0]]))
- $parent=$controls[$object[0]];
- else
- continue;
- if(isset($object[2])) // component
- {
- $component=Prado::createComponent($object[1]);
- $properties=&$object[2];
- if($component instanceof TControl)
- {
- if($component instanceof TOutputCache)
- $component->setCacheKeyPrefix($this->_hashCode.$key);
- $component->setTemplateControl($tplControl);
- if(isset($properties['id']))
- {
- if(is_array($properties['id']))
- $properties['id']=$component->evaluateExpression($properties['id'][1]);
- $tplControl->registerObject($properties['id'],$component);
- }
- if(isset($properties['skinid']))
- {
- if(is_array($properties['skinid']))
- $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
- else
- $component->setSkinID($properties['skinid']);
- unset($properties['skinid']);
- }
-
- $component->trackViewState(false);
-
- $component->applyStyleSheetSkin($page);
- foreach($properties as $name=>$value)
- $this->configureControl($component,$name,$value);
-
- $component->trackViewState(true);
-
- if($parent===$parentControl)
- $directChildren[]=$component;
- else
- $component->createdOnTemplate($parent);
- if($component->getAllowChildControls())
- $controls[$key]=$component;
- }
- else if($component instanceof TComponent)
- {
- $controls[$key]=$component;
- if(isset($properties['id']))
- {
- if(is_array($properties['id']))
- $properties['id']=$component->evaluateExpression($properties['id'][1]);
- $tplControl->registerObject($properties['id'],$component);
- if(!$component->hasProperty('id'))
- unset($properties['id']);
- }
- foreach($properties as $name=>$value)
- $this->configureComponent($component,$name,$value);
- if($parent===$parentControl)
- $directChildren[]=$component;
- else
- $component->createdOnTemplate($parent);
- }
- }
- else
- {
- if($object[1] instanceof TCompositeLiteral)
- {
- // need to clone a new object because the one in template is reused
- $o=clone $object[1];
- $o->setContainer($tplControl);
- if($parent===$parentControl)
- $directChildren[]=$o;
- else
- $parent->addParsedObject($o);
- }
- else
- {
- if($parent===$parentControl)
- $directChildren[]=$object[1];
- else
- $parent->addParsedObject($object[1]);
- }
- }
- }
- // delay setting parent till now because the parent may cause
- // the child to do lifecycle catchup which may cause problem
- // if the child needs its own child controls.
- foreach($directChildren as $control)
- {
- if($control instanceof TComponent)
- $control->createdOnTemplate($parentControl);
- else
- $parentControl->addParsedObject($control);
- }
- }
-
- /**
- * Configures a property/event of a control.
- * @param TControl control to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureControl($control,$name,$value)
- {
- if(strncasecmp($name,'on',2)===0) // is an event
- $this->configureEvent($control,$name,$value,$control);
- else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
- $this->configureProperty($control,$name,$value);
- else // is a subproperty
- $this->configureSubProperty($control,$name,$value);
- }
-
- /**
- * Configures a property of a non-control component.
- * @param TComponent component to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureComponent($component,$name,$value)
- {
- if(strpos($name,'.')===false) // is a simple property or custom attribute
- $this->configureProperty($component,$name,$value);
- else // is a subproperty
- $this->configureSubProperty($component,$name,$value);
- }
-
- /**
- * Configures an event for a control.
- * @param TControl control to be configured
- * @param string event name
- * @param string event handler
- * @param TControl context control
- */
- protected function configureEvent($control,$name,$value,$contextControl)
- {
- if(strpos($value,'.')===false)
- $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
- else
- $control->attachEventHandler($name,array($contextControl,$value));
- }
-
- /**
- * Configures a simple property for a component.
- * @param TComponent component to be configured
- * @param string property name
- * @param mixed property initial value
- */
- protected function configureProperty($component,$name,$value)
- {
- if(is_array($value))
- {
- switch($value[0])
- {
- case self::CONFIG_DATABIND:
- $component->bindProperty($name,$value[1]);
- break;
- case self::CONFIG_EXPRESSION:
- if($component instanceof TControl)
- $component->autoBindProperty($name,$value[1]);
- else
- {
- $setter='set'.$name;
- $component->$setter($this->_tplControl->evaluateExpression($value[1]));
- }
- break;
- case self::CONFIG_TEMPLATE:
- $setter='set'.$name;
- $component->$setter($value[1]);
- break;
- case self::CONFIG_ASSET: // asset URL
- $setter='set'.$name;
- $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
- $component->$setter($url);
- break;
- case self::CONFIG_PARAMETER: // application parameter
- $setter='set'.$name;
- $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case self::CONFIG_LOCALIZATION:
- $setter='set'.$name;
- $component->$setter(Prado::localize($value[1]));
- break;
- default: // an error if reaching here
- throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
- break;
- }
- }
- else
- {
- if (substr($name,0,2)=='js')
- if ($value and !($value instanceof TJavaScriptLiteral))
- $value = new TJavaScriptLiteral($value);
- $setter='set'.$name;
- $component->$setter($value);
- }
- }
-
- /**
- * Configures a subproperty for a component.
- * @param TComponent component to be configured
- * @param string subproperty name
- * @param mixed subproperty initial value
- */
- protected function configureSubProperty($component,$name,$value)
- {
- if(is_array($value))
- {
- switch($value[0])
- {
- case self::CONFIG_DATABIND: // databinding
- $component->bindProperty($name,$value[1]);
- break;
- case self::CONFIG_EXPRESSION: // expression
- if($component instanceof TControl)
- $component->autoBindProperty($name,$value[1]);
- else
- $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
- break;
- case self::CONFIG_TEMPLATE:
- $component->setSubProperty($name,$value[1]);
- break;
- case self::CONFIG_ASSET: // asset URL
- $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
- $component->setSubProperty($name,$url);
- break;
- case self::CONFIG_PARAMETER: // application parameter
- $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case self::CONFIG_LOCALIZATION:
- $component->setSubProperty($name,Prado::localize($value[1]));
- break;
- default: // an error if reaching here
- throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
- break;
- }
- }
- else
- $component->setSubProperty($name,$value);
- }
-
- /**
- * Parses a template string.
- *
- * This template parser recognizes five types of data:
- * regular string, well-formed component tags, well-formed property tags, directives, and expressions.
- *
- * The parsing result is returned as an array. Each array element can be of three types:
- * - a string, 0: container index; 1: string content;
- * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs)
- * If a directive is found in the template, it will be parsed and can be
- * retrieved via {@link getDirective}, which returns an array consisting of
- * name-value pairs in the directive.
- *
- * Note, attribute names are treated as case-insensitive and will be turned into lower cases.
- * Component and directive types are case-sensitive.
- * Container index is the index to the array element that stores the container object.
- * If an object has no container, its container index is -1.
- *
- * @param string the template string
- * @throws TConfigurationException if a parsing error is encountered
- */
- protected function parse($input)
- {
- $input=$this->preprocess($input);
- $tpl=&$this->_tpl;
- $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
- $expectPropEnd=false;
- $textStart=0;
- $stack=array();
- $container=-1;
- $matchEnd=0;
- $c=0;
- $this->_directive=null;
- try
- {
- for($i=0;$i<$n;++$i)
- {
- $match=&$matches[$i];
- $str=$match[0][0];
- $matchStart=$match[0][1];
- $matchEnd=$matchStart+strlen($str)-1;
- if(strpos($str,'<com:')===0) // opening component tag
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $type=$match[1][0];
- $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
- $this->validateAttributes($type,$attributes);
- $tpl[$c++]=array($container,$type,$attributes);
- if($str[strlen($str)-2]!=='/') // open tag
- {
- $stack[] = $type;
- $container=$c-1;
- }
- }
- else if(strpos($str,'</com:')===0) // closing component tag
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $type=$match[1][0];
-
- if(empty($stack))
- throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
-
- $name=array_pop($stack);
- if($name!==$type)
- {
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- $container=$tpl[$container][0];
- }
- else if(strpos($str,'<%@')===0) // directive
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- if(isset($tpl[0]) || $this->_directive!==null)
- throw new TConfigurationException('template_directive_nonunique');
- $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
- }
- else if(strpos($str,'<%')===0) // expression
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $literal=trim($match[5][0]);
- if($str[2]==='=') // expression
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
- else if($str[2]==='%') // statements
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
- else if($str[2]==='#')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
- else if($str[2]==='$')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
- else if($str[2]==='~')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
- else if($str[2]==='/')
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
- else if($str[2]==='[')
- {
- $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
- $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
- }
- }
- else if(strpos($str,'<prop:')===0) // opening property
- {
- if(strrpos($str,'/>')===strlen($str)-2) //subproperties
- {
- if($expectPropEnd)
- continue;
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $prop=strtolower($match[6][0]);
- $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
- $attributes=array();
- foreach($attrs as $name=>$value)
- $attributes[$prop.'.'.$name]=$value;
- $type=$tpl[$container][1];
- $this->validateAttributes($type,$attributes);
- foreach($attributes as $name=>$value)
- {
- if(isset($tpl[$container][2][$name]))
- throw new TConfigurationException('template_property_duplicated',$name);
- $tpl[$container][2][$name]=$value;
- }
- }
- else // regular property
- {
- $prop=strtolower($match[3][0]);
- $stack[] = '@'.$prop;
- if(!$expectPropEnd)
- {
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- $expectPropEnd=true;
- }
- }
- }
- else if(strpos($str,'</prop:')===0) // closing property
- {
- $prop=strtolower($match[3][0]);
- if(empty($stack))
- throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
- $name=array_pop($stack);
- if($name!=='@'.$prop)
- {
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
- {
- if($matchStart>$textStart)
- {
- $value=substr($input,$textStart,$matchStart-$textStart);
- if(substr($prop,-8,8)==='template')
- $value=$this->parseTemplateProperty($value,$textStart);
- else
- $value=$this->parseAttribute($value);
- if($container>=0)
- {
- $type=$tpl[$container][1];
- $this->validateAttributes($type,array($prop=>$value));
- if(isset($tpl[$container][2][$prop]))
- throw new TConfigurationException('template_property_duplicated',$prop);
- $tpl[$container][2][$prop]=$value;
- }
- else // a property for the template control
- $this->_directive[$prop]=$value;
- $textStart=$matchEnd+1;
- }
- $expectPropEnd=false;
- }
- }
- else if(strpos($str,'<!--')===0) // comments
- {
- if($expectPropEnd)
- throw new TConfigurationException('template_comments_forbidden');
- if($matchStart>$textStart)
- $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
- $textStart=$matchEnd+1;
- }
- else
- throw new TConfigurationException('template_matching_unexpected',$match);
- }
- if(!empty($stack))
- {
- $name=array_pop($stack);
- $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
- throw new TConfigurationException('template_closingtag_expected',$tag);
- }
- if($textStart<strlen($input))
- $tpl[$c++]=array($container,substr($input,$textStart));
- }
- catch(Exception $e)
- {
- if(($e instanceof TException) && ($e instanceof TTemplateException))
- throw $e;
- if($matchEnd===0)
- $line=$this->_startingLine+1;
- else
- $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
- $this->handleException($e,$line,$input);
- }
-
- if($this->_directive===null)
- $this->_directive=array();
-
- // optimization by merging consecutive strings, expressions, statements and bindings
- $objects=array();
- $parent=null;
- $merged=array();
- foreach($tpl as $id=>$object)
- {
- if(isset($object[2]) || $object[0]!==$parent)
- {
- if($parent!==null)
- {
- if(count($merged[1])===1 && is_string($merged[1][0]))
- $objects[$id-1]=array($merged[0],$merged[1][0]);
- else
- $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
- }
- if(isset($object[2]))
- {
- $parent=null;
- $objects[$id]=$object;
- }
- else
- {
- $parent=$object[0];
- $merged=array($parent,array($object[1]));
- }
- }
- else
- $merged[1][]=$object[1];
- }
- if($parent!==null)
- {
- if(count($merged[1])===1 && is_string($merged[1][0]))
- $objects[$id]=array($merged[0],$merged[1][0]);
- else
- $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
- }
- $tpl=$objects;
- return $objects;
- }
-
- /**
- * Parses the attributes of a tag from a string.
- * @param string the string to be parsed.
- * @return array attribute values indexed by names.
- */
- protected function parseAttributes($str,$offset)
- {
- if($str==='')
- return array();
- $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
- $attributes=array();
- $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
- for($i=0;$i<$n;++$i)
- {
- $match=&$matches[$i];
- $name=strtolower($match[1][0]);
- if(isset($attributes[$name]))
- throw new TConfigurationException('template_property_duplicated',$name);
- $value=$match[2][0];
- if(substr($name,-8,8)==='template')
- {
- if($value[0]==='\'' || $value[0]==='"')
- $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
- else
- $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
- }
- else
- {
- if($value[0]==='\'' || $value[0]==='"')
- $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
- else
- $attributes[$name]=$this->parseAttribute($value);
- }
- }
- return $attributes;
- }
-
- protected function parseTemplateProperty($content,$offset)
- {
- $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
- return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
- }
-
- /**
- * Parses a single attribute.
- * @param string the string to be parsed.
- * @return array attribute initialization
- */
- protected function parseAttribute($value)
- {
- if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
- {
- $isDataBind=false;
- $textStart=0;
- $expr='';
- for($i=0;$i<$n;++$i)
- {
- $match=$matches[0][$i];
- $token=$match[0];
- $offset=$match[1];
- $length=strlen($token);
- if($token[2]==='#')
- $isDataBind=true;
- if($offset>$textStart)
- $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
- $expr.='.('.substr($token,3,$length-5).')';
- $textStart=$offset+$length;
- }
- $length=strlen($value);
- if($length>$textStart)
- $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
- if($isDataBind)
- return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
- else
- return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
- }
- else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
- {
- $value=$matches[1];
- if($value[2]==='~')
- return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
- elseif($value[2]==='[')
- return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
- elseif($value[2]==='$')
- return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
- elseif($value[2]==='/') {
- $literal = trim(substr($value,3,strlen($value)-5));
- return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'");
- }
- }
- else
- return $value;
- }
-
- protected function validateAttributes($type,$attributes)
- {
- Prado::using($type);
- if(($pos=strrpos($type,'.'))!==false)
- $className=substr($type,$pos+1);
- else
- $className=$type;
- $class=new ReflectionClass($className);
- if(is_subclass_of($className,'TControl') || $className==='TControl')
- {
- foreach($attributes as $name=>$att)
- {
- if(($pos=strpos($name,'.'))!==false)
- {
- // a subproperty, so the first segment must be readable
- $subname=substr($name,0,$pos);
- if(!$class->hasMethod('get'.$subname))
- throw new TConfigurationException('template_property_unknown',$type,$subname);
- }
- else if(strncasecmp($name,'on',2)===0)
- {
- // an event
- if(!$class->hasMethod($name))
- throw new TConfigurationException('template_event_unknown',$type,$name);
- else if(!is_string($att))
- throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
- }
- else
- {
- // a simple property
- if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name)) )
- {
- if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
- throw new TConfigurationException('template_property_readonly',$type,$name);
- else
- throw new TConfigurationException('template_property_unknown',$type,$name);
- }
- else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
- {
- if(strcasecmp($name,'id')===0)
- throw new TConfigurationException('template_controlid_invalid',$type);
- else if(strcasecmp($name,'skinid')===0)
- throw new TConfigurationException('template_controlskinid_invalid',$type);
- }
- }
- }
- }
- else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
- {
- foreach($attributes as $name=>$att)
- {
- if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
- throw new TConfigurationException('template_databind_forbidden',$type,$name);
- if(($pos=strpos($name,'.'))!==false)
- {
- // a subproperty, so the first segment must be readable
- $subname=substr($name,0,$pos);
- if(!$class->hasMethod('get'.$subname))
- throw new TConfigurationException('template_property_unknown',$type,$subname);
- }
- else if(strncasecmp($name,'on',2)===0)
- throw new TConfigurationException('template_event_forbidden',$type,$name);
- else
- {
- // id is still alowed for TComponent, even if id property doesn't exist
- if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
- {
- if($class->hasMethod('get'.$name))
- throw new TConfigurationException('template_property_readonly',$type,$name);
- else
- throw new TConfigurationException('template_property_unknown',$type,$name);
- }
- }
- }
- }
- else
- throw new TConfigurationException('template_component_required',$type);
- }
-
- /**
- * @return array list of included external template files
- */
- public function getIncludedFiles()
- {
- return $this->_includedFiles;
- }
-
- /**
- * Handles template parsing exception.
- * This method rethrows the exception caught during template parsing.
- * It adjusts the error location by giving out correct error line number and source file.
- * @param Exception template exception
- * @param int line number
- * @param string template string if no source file is used
- */
- protected function handleException($e,$line,$input=null)
- {
- $srcFile=$this->_tplFile;
-
- if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name
- {
- for($i=$n-1;$i>=0;--$i)
- {
- if($this->_includeAtLine[$i]<=$line)
- {
- if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
- {
- $line=$line-$this->_includeAtLine[$i]+1;
- $srcFile=$this->_includedFiles[$i];
- break;
- }
- else
- $line=$line-$this->_includeLines[$i]+1;
- }
- }
- }
- $exception=new TTemplateException('template_format_invalid',$e->getMessage());
- $exception->setLineNumber($line);
- if(!empty($srcFile))
- $exception->setTemplateFile($srcFile);
- else
- $exception->setTemplateSource($input);
- throw $exception;
- }
-
- /**
- * Preprocesses the template string by including external templates
- * @param string template string
- * @return string expanded template string
- */
- protected function preprocess($input)
- {
- if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
- {
- for($i=0;$i<$n;++$i)
- {
- $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
- if($filePath!==null && is_file($filePath))
- $this->_includedFiles[]=$filePath;
- else
- {
- $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
- $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
- }
- }
- $base=0;
- for($i=0;$i<$n;++$i)
- {
- $ext=file_get_contents($this->_includedFiles[$i]);
- $length=strlen($matches[$i][0][0]);
- $offset=$base+$matches[$i][0][1];
- $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
- $this->_includeLines[$i]=count(explode("\n",$ext));
- $input=substr_replace($input,$ext,$offset,$length);
- $base+=strlen($ext)-$length;
- }
- }
-
- return $input;
- }
-}
-
+<?php
+/**
+ * TTemplateManager and TTemplate class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * Includes TOutputCache class file
+ */
+Prado::using('System.Web.UI.WebControls.TOutputCache');
+
+/**
+ * TTemplateManager class
+ *
+ * TTemplateManager manages the loading and parsing of control templates.
+ *
+ * There are two ways of loading a template, either by the associated template
+ * control class name, or the template file name.
+ * The former is via calling {@link getTemplateByClassName}, which tries to
+ * locate the corresponding template file under the directory containing
+ * the class file. The name of the template file is the class name with
+ * the extension '.tpl'. To load a template from a template file path,
+ * call {@link getTemplateByFileName}.
+ *
+ * By default, TTemplateManager is registered with {@link TPageService} as the
+ * template manager module that can be accessed via {@link TPageService::getTemplateManager()}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplateManager extends TModule
+{
+ /**
+ * Template file extension
+ */
+ const TEMPLATE_FILE_EXT='.tpl';
+ /**
+ * Prefix of the cache variable name for storing parsed templates
+ */
+ const TEMPLATE_CACHE_PREFIX='prado:template:';
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * It starts output buffer if it is enabled.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ $this->getService()->setTemplateManager($this);
+ }
+
+ /**
+ * Loads the template corresponding to the specified class name.
+ * @return ITemplate template for the class name, null if template doesn't exist.
+ */
+ public function getTemplateByClassName($className)
+ {
+ $class=new ReflectionClass($className);
+ $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT;
+ return $this->getTemplateByFileName($tplFile);
+ }
+
+ /**
+ * Loads the template from the specified file.
+ * @return ITemplate template parsed from the specified file, null if the file doesn't exist.
+ */
+ public function getTemplateByFileName($fileName)
+ {
+ if(($fileName=$this->getLocalizedTemplate($fileName))!==null)
+ {
+ Prado::trace("Loading template $fileName",'System.Web.UI.TTemplateManager');
+ if(($cache=$this->getApplication()->getCache())===null)
+ return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ else
+ {
+ $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName);
+ if(is_array($array))
+ {
+ list($template,$timestamps)=$array;
+ if($this->getApplication()->getMode()===TApplicationMode::Performance)
+ return $template;
+ $cacheValid=true;
+ foreach($timestamps as $tplFile=>$timestamp)
+ {
+ if(!is_file($tplFile) || filemtime($tplFile)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ if($cacheValid)
+ return $template;
+ }
+ $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName);
+ $includedFiles=$template->getIncludedFiles();
+ $timestamps=array();
+ $timestamps[$fileName]=filemtime($fileName);
+ foreach($includedFiles as $includedFile)
+ $timestamps[$includedFile]=filemtime($includedFile);
+ $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps));
+ return $template;
+ }
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Finds a localized template file.
+ * @param string template file.
+ * @return string|null a localized template file if found, null otherwise.
+ */
+ protected function getLocalizedTemplate($filename)
+ {
+ if(($app=$this->getApplication()->getGlobalization(false))===null)
+ return is_file($filename)?$filename:null;
+ foreach($app->getLocalizedResource($filename) as $file)
+ {
+ if(($file=realpath($file))!==false && is_file($file))
+ return $file;
+ }
+ return null;
+ }
+}
+
+/**
+ * TTemplate implements PRADO template parsing logic.
+ * A TTemplate object represents a parsed PRADO control template.
+ * It can instantiate the template as child controls of a specified control.
+ * The template format is like HTML, with the following special tags introduced,
+ * - component tags: a component tag represents the configuration of a component.
+ * The tag name is in the format of com:ComponentType, where ComponentType is the component
+ * class name. Component tags must be well-formed. Attributes of the component tag
+ * are treated as either property initial values, event handler attachment, or regular
+ * tag attributes.
+ * - property tags: property tags are used to set large block of attribute values.
+ * The property tag name is in the format of <prop:AttributeName> where AttributeName
+ * can be a property name, an event name or a regular tag attribute name.
+ * - group subproperty tags: subproperties of a common property can be configured using
+ * <prop:MainProperty SubProperty1="Value1" SubProperty2="Value2" .../>
+ * - directive: directive specifies the property values for the template owner.
+ * It is in the format of <%@ property name-value pairs %>;
+ * - expressions: They are in the format of <%= PHP expression %> and <%% PHP statements %>
+ * - comments: There are two kinds of comments, regular HTML comments and special template comments.
+ * The former is in the format of <!-- comments -->, which will be treated as text strings.
+ * The latter is in the format of <!-- comments --!>, which will be stripped out.
+ *
+ * Tags other than the above are not required to be well-formed.
+ *
+ * A TTemplate object represents a parsed PRADO template. To instantiate the template
+ * for a particular control, call {@link instantiateIn($control)}, which
+ * will create and intialize all components specified in the template and
+ * set their parent as $control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTemplate extends TApplicationComponent implements ITemplate
+{
+ /**
+ * '<!--.*?--!>' - template comments
+ * '<!--.*?-->' - HTML comments
+ * '<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>' - component tags
+ * '<\/?prop:([\w\.]+)\s*>' - property tags
+ * '<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>' - directives
+ * '<%[%#~\/\\$=\\[](.*?)%>' - expressions
+ * '<prop:([\w\.]+)((?:\s*[\w\.]+=\'.*?\'|\s*[\w\.]+=".*?"|\s*[\w\.]+=<%.*?%>)*)\s*\/>' - group subproperty tags
+ */
+ const REGEX_RULES='/<!--.*?--!>|<!---.*?--->|<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|<prop:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/>/msS';
+
+ /**
+ * Different configurations of component property/event/attribute
+ */
+ const CONFIG_DATABIND=0;
+ const CONFIG_EXPRESSION=1;
+ const CONFIG_ASSET=2;
+ const CONFIG_PARAMETER=3;
+ const CONFIG_LOCALIZATION=4;
+ const CONFIG_TEMPLATE=5;
+
+ /**
+ * @var array list of component tags and strings
+ */
+ private $_tpl=array();
+ /**
+ * @var array list of directive settings
+ */
+ private $_directive=array();
+ /**
+ * @var string context path
+ */
+ private $_contextPath;
+ /**
+ * @var string template file path (if available)
+ */
+ private $_tplFile=null;
+ /**
+ * @var integer the line number that parsing starts from (internal use)
+ */
+ private $_startingLine=0;
+ /**
+ * @var string template content to be parsed
+ */
+ private $_content;
+ /**
+ * @var boolean whether this template is a source template
+ */
+ private $_sourceTemplate=true;
+ /**
+ * @var string hash code of the template
+ */
+ private $_hashCode='';
+ private $_tplControl=null;
+ private $_includedFiles=array();
+ private $_includeAtLine=array();
+ private $_includeLines=array();
+
+
+ /**
+ * Constructor.
+ * The template will be parsed after construction.
+ * @param string the template string
+ * @param string the template context directory
+ * @param string the template file, null if no file
+ * @param integer the line number that parsing starts from (internal use)
+ * @param boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true)
+ {
+ $this->_sourceTemplate=$sourceTemplate;
+ $this->_contextPath=$contextPath;
+ $this->_tplFile=$tplFile;
+ $this->_startingLine=$startingLine;
+ $this->_content=$template;
+ $this->_hashCode=md5($template);
+ $this->parse($template);
+ $this->_content=null; // reset to save memory
+ }
+
+ /**
+ * @return string template file path if available, null otherwise.
+ */
+ public function getTemplateFile()
+ {
+ return $this->_tplFile;
+ }
+
+ /**
+ * @return boolean whether this template is a source template, i.e., this template is loaded from
+ * some external storage rather than from within another template.
+ */
+ public function getIsSourceTemplate()
+ {
+ return $this->_sourceTemplate;
+ }
+
+ /**
+ * @return string context directory path
+ */
+ public function getContextPath()
+ {
+ return $this->_contextPath;
+ }
+
+ /**
+ * @return array name-value pairs declared in the directive
+ */
+ public function getDirective()
+ {
+ return $this->_directive;
+ }
+
+ /**
+ * @return string hash code that can be used to identify the template
+ */
+ public function getHashCode()
+ {
+ return $this->_hashCode;
+ }
+
+ /**
+ * @return array the parsed template
+ */
+ public function &getItems()
+ {
+ return $this->_tpl;
+ }
+
+ /**
+ * Instantiates the template.
+ * Content in the template will be instantiated as components and text strings
+ * and passed to the specified parent control.
+ * @param TControl the control who owns the template
+ * @param TControl the control who will become the root parent of the controls on the template. If null, it uses the template control.
+ */
+ public function instantiateIn($tplControl,$parentControl=null)
+ {
+ $this->_tplControl=$tplControl;
+ if($parentControl===null)
+ $parentControl=$tplControl;
+ if(($page=$tplControl->getPage())===null)
+ $page=$this->getService()->getRequestedPage();
+ $controls=array();
+ $directChildren=array();
+ foreach($this->_tpl as $key=>$object)
+ {
+ if($object[0]===-1)
+ $parent=$parentControl;
+ else if(isset($controls[$object[0]]))
+ $parent=$controls[$object[0]];
+ else
+ continue;
+ if(isset($object[2])) // component
+ {
+ $component=Prado::createComponent($object[1]);
+ $properties=&$object[2];
+ if($component instanceof TControl)
+ {
+ if($component instanceof TOutputCache)
+ $component->setCacheKeyPrefix($this->_hashCode.$key);
+ $component->setTemplateControl($tplControl);
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ }
+ if(isset($properties['skinid']))
+ {
+ if(is_array($properties['skinid']))
+ $component->setSkinID($component->evaluateExpression($properties['skinid'][1]));
+ else
+ $component->setSkinID($properties['skinid']);
+ unset($properties['skinid']);
+ }
+
+ $component->trackViewState(false);
+
+ $component->applyStyleSheetSkin($page);
+ foreach($properties as $name=>$value)
+ $this->configureControl($component,$name,$value);
+
+ $component->trackViewState(true);
+
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ if($component->getAllowChildControls())
+ $controls[$key]=$component;
+ }
+ else if($component instanceof TComponent)
+ {
+ $controls[$key]=$component;
+ if(isset($properties['id']))
+ {
+ if(is_array($properties['id']))
+ $properties['id']=$component->evaluateExpression($properties['id'][1]);
+ $tplControl->registerObject($properties['id'],$component);
+ if(!$component->hasProperty('id'))
+ unset($properties['id']);
+ }
+ foreach($properties as $name=>$value)
+ $this->configureComponent($component,$name,$value);
+ if($parent===$parentControl)
+ $directChildren[]=$component;
+ else
+ $component->createdOnTemplate($parent);
+ }
+ }
+ else
+ {
+ if($object[1] instanceof TCompositeLiteral)
+ {
+ // need to clone a new object because the one in template is reused
+ $o=clone $object[1];
+ $o->setContainer($tplControl);
+ if($parent===$parentControl)
+ $directChildren[]=$o;
+ else
+ $parent->addParsedObject($o);
+ }
+ else
+ {
+ if($parent===$parentControl)
+ $directChildren[]=$object[1];
+ else
+ $parent->addParsedObject($object[1]);
+ }
+ }
+ }
+ // delay setting parent till now because the parent may cause
+ // the child to do lifecycle catchup which may cause problem
+ // if the child needs its own child controls.
+ foreach($directChildren as $control)
+ {
+ if($control instanceof TComponent)
+ $control->createdOnTemplate($parentControl);
+ else
+ $parentControl->addParsedObject($control);
+ }
+ }
+
+ /**
+ * Configures a property/event of a control.
+ * @param TControl control to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureControl($control,$name,$value)
+ {
+ if(strncasecmp($name,'on',2)===0) // is an event
+ $this->configureEvent($control,$name,$value,$control);
+ else if(($pos=strrpos($name,'.'))===false) // is a simple property or custom attribute
+ $this->configureProperty($control,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($control,$name,$value);
+ }
+
+ /**
+ * Configures a property of a non-control component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureComponent($component,$name,$value)
+ {
+ if(strpos($name,'.')===false) // is a simple property or custom attribute
+ $this->configureProperty($component,$name,$value);
+ else // is a subproperty
+ $this->configureSubProperty($component,$name,$value);
+ }
+
+ /**
+ * Configures an event for a control.
+ * @param TControl control to be configured
+ * @param string event name
+ * @param string event handler
+ * @param TControl context control
+ */
+ protected function configureEvent($control,$name,$value,$contextControl)
+ {
+ if(strpos($value,'.')===false)
+ $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value));
+ else
+ $control->attachEventHandler($name,array($contextControl,$value));
+ }
+
+ /**
+ * Configures a simple property for a component.
+ * @param TComponent component to be configured
+ * @param string property name
+ * @param mixed property initial value
+ */
+ protected function configureProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND:
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION:
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ {
+ $setter='set'.$name;
+ $component->$setter($this->_tplControl->evaluateExpression($value[1]));
+ }
+ break;
+ case self::CONFIG_TEMPLATE:
+ $setter='set'.$name;
+ $component->$setter($value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $setter='set'.$name;
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->$setter($url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $setter='set'.$name;
+ $component->$setter($this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $setter='set'.$name;
+ $component->$setter(Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ {
+ if (substr($name,0,2)=='js')
+ if ($value and !($value instanceof TJavaScriptLiteral))
+ $value = new TJavaScriptLiteral($value);
+ $setter='set'.$name;
+ $component->$setter($value);
+ }
+ }
+
+ /**
+ * Configures a subproperty for a component.
+ * @param TComponent component to be configured
+ * @param string subproperty name
+ * @param mixed subproperty initial value
+ */
+ protected function configureSubProperty($component,$name,$value)
+ {
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case self::CONFIG_DATABIND: // databinding
+ $component->bindProperty($name,$value[1]);
+ break;
+ case self::CONFIG_EXPRESSION: // expression
+ if($component instanceof TControl)
+ $component->autoBindProperty($name,$value[1]);
+ else
+ $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1]));
+ break;
+ case self::CONFIG_TEMPLATE:
+ $component->setSubProperty($name,$value[1]);
+ break;
+ case self::CONFIG_ASSET: // asset URL
+ $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]);
+ $component->setSubProperty($name,$url);
+ break;
+ case self::CONFIG_PARAMETER: // application parameter
+ $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case self::CONFIG_LOCALIZATION:
+ $component->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default: // an error if reaching here
+ throw new TConfigurationException('template_tag_unexpected',$name,$value[1]);
+ break;
+ }
+ }
+ else
+ $component->setSubProperty($name,$value);
+ }
+
+ /**
+ * Parses a template string.
+ *
+ * This template parser recognizes five types of data:
+ * regular string, well-formed component tags, well-formed property tags, directives, and expressions.
+ *
+ * The parsing result is returned as an array. Each array element can be of three types:
+ * - a string, 0: container index; 1: string content;
+ * - a component tag, 0: container index; 1: component type; 2: attributes (name=>value pairs)
+ * If a directive is found in the template, it will be parsed and can be
+ * retrieved via {@link getDirective}, which returns an array consisting of
+ * name-value pairs in the directive.
+ *
+ * Note, attribute names are treated as case-insensitive and will be turned into lower cases.
+ * Component and directive types are case-sensitive.
+ * Container index is the index to the array element that stores the container object.
+ * If an object has no container, its container index is -1.
+ *
+ * @param string the template string
+ * @throws TConfigurationException if a parsing error is encountered
+ */
+ protected function parse($input)
+ {
+ $input=$this->preprocess($input);
+ $tpl=&$this->_tpl;
+ $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ $expectPropEnd=false;
+ $textStart=0;
+ $stack=array();
+ $container=-1;
+ $matchEnd=0;
+ $c=0;
+ $this->_directive=null;
+ try
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $str=$match[0][0];
+ $matchStart=$match[0][1];
+ $matchEnd=$matchStart+strlen($str)-1;
+ if(strpos($str,'<com:')===0) // opening component tag
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+ $attributes=$this->parseAttributes($match[2][0],$match[2][1]);
+ $this->validateAttributes($type,$attributes);
+ $tpl[$c++]=array($container,$type,$attributes);
+ if($str[strlen($str)-2]!=='/') // open tag
+ {
+ $stack[] = $type;
+ $container=$c-1;
+ }
+ }
+ else if(strpos($str,'</com:')===0) // closing component tag
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $type=$match[1][0];
+
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</com:$type>");
+
+ $name=array_pop($stack);
+ if($name!==$type)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ $container=$tpl[$container][0];
+ }
+ else if(strpos($str,'<%@')===0) // directive
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ if(isset($tpl[0]) || $this->_directive!==null)
+ throw new TConfigurationException('template_directive_nonunique');
+ $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]);
+ }
+ else if(strpos($str,'<%')===0) // expression
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $literal=trim($match[5][0]);
+ if($str[2]==='=') // expression
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal));
+ else if($str[2]==='%') // statements
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal));
+ else if($str[2]==='#')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal));
+ else if($str[2]==='$')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')"));
+ else if($str[2]==='~')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')"));
+ else if($str[2]==='/')
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'"));
+ else if($str[2]==='[')
+ {
+ $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\"));
+ $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')"));
+ }
+ }
+ else if(strpos($str,'<prop:')===0) // opening property
+ {
+ if(strrpos($str,'/>')===strlen($str)-2) //subproperties
+ {
+ if($expectPropEnd)
+ continue;
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $prop=strtolower($match[6][0]);
+ $attrs=$this->parseAttributes($match[7][0],$match[7][1]);
+ $attributes=array();
+ foreach($attrs as $name=>$value)
+ $attributes[$prop.'.'.$name]=$value;
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,$attributes);
+ foreach($attributes as $name=>$value)
+ {
+ if(isset($tpl[$container][2][$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $tpl[$container][2][$name]=$value;
+ }
+ }
+ else // regular property
+ {
+ $prop=strtolower($match[3][0]);
+ $stack[] = '@'.$prop;
+ if(!$expectPropEnd)
+ {
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ $expectPropEnd=true;
+ }
+ }
+ }
+ else if(strpos($str,'</prop:')===0) // closing property
+ {
+ $prop=strtolower($match[3][0]);
+ if(empty($stack))
+ throw new TConfigurationException('template_closingtag_unexpected',"</prop:$prop>");
+ $name=array_pop($stack);
+ if($name!=='@'.$prop)
+ {
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if(($last=count($stack))<1 || $stack[$last-1][0]!=='@')
+ {
+ if($matchStart>$textStart)
+ {
+ $value=substr($input,$textStart,$matchStart-$textStart);
+ if(substr($prop,-8,8)==='template')
+ $value=$this->parseTemplateProperty($value,$textStart);
+ else
+ $value=$this->parseAttribute($value);
+ if($container>=0)
+ {
+ $type=$tpl[$container][1];
+ $this->validateAttributes($type,array($prop=>$value));
+ if(isset($tpl[$container][2][$prop]))
+ throw new TConfigurationException('template_property_duplicated',$prop);
+ $tpl[$container][2][$prop]=$value;
+ }
+ else // a property for the template control
+ $this->_directive[$prop]=$value;
+ $textStart=$matchEnd+1;
+ }
+ $expectPropEnd=false;
+ }
+ }
+ else if(strpos($str,'<!--')===0) // comments
+ {
+ if($expectPropEnd)
+ throw new TConfigurationException('template_comments_forbidden');
+ if($matchStart>$textStart)
+ $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart));
+ $textStart=$matchEnd+1;
+ }
+ else
+ throw new TConfigurationException('template_matching_unexpected',$match);
+ }
+ if(!empty($stack))
+ {
+ $name=array_pop($stack);
+ $tag=$name[0]==='@' ? '</prop:'.substr($name,1).'>' : "</com:$name>";
+ throw new TConfigurationException('template_closingtag_expected',$tag);
+ }
+ if($textStart<strlen($input))
+ $tpl[$c++]=array($container,substr($input,$textStart));
+ }
+ catch(Exception $e)
+ {
+ if(($e instanceof TException) && ($e instanceof TTemplateException))
+ throw $e;
+ if($matchEnd===0)
+ $line=$this->_startingLine+1;
+ else
+ $line=$this->_startingLine+count(explode("\n",substr($input,0,$matchEnd+1)));
+ $this->handleException($e,$line,$input);
+ }
+
+ if($this->_directive===null)
+ $this->_directive=array();
+
+ // optimization by merging consecutive strings, expressions, statements and bindings
+ $objects=array();
+ $parent=null;
+ $merged=array();
+ foreach($tpl as $id=>$object)
+ {
+ if(isset($object[2]) || $object[0]!==$parent)
+ {
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id-1]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id-1]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ if(isset($object[2]))
+ {
+ $parent=null;
+ $objects[$id]=$object;
+ }
+ else
+ {
+ $parent=$object[0];
+ $merged=array($parent,array($object[1]));
+ }
+ }
+ else
+ $merged[1][]=$object[1];
+ }
+ if($parent!==null)
+ {
+ if(count($merged[1])===1 && is_string($merged[1][0]))
+ $objects[$id]=array($merged[0],$merged[1][0]);
+ else
+ $objects[$id]=array($merged[0],new TCompositeLiteral($merged[1]));
+ }
+ $tpl=$objects;
+ return $objects;
+ }
+
+ /**
+ * Parses the attributes of a tag from a string.
+ * @param string the string to be parsed.
+ * @return array attribute values indexed by names.
+ */
+ protected function parseAttributes($str,$offset)
+ {
+ if($str==='')
+ return array();
+ $pattern='/([\w\.\-]+)\s*=\s*(\'.*?\'|".*?"|<%.*?%>)/msS';
+ $attributes=array();
+ $n=preg_match_all($pattern,$str,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
+ for($i=0;$i<$n;++$i)
+ {
+ $match=&$matches[$i];
+ $name=strtolower($match[1][0]);
+ if(isset($attributes[$name]))
+ throw new TConfigurationException('template_property_duplicated',$name);
+ $value=$match[2][0];
+ if(substr($name,-8,8)==='template')
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseTemplateProperty(substr($value,1,strlen($value)-2),$match[2][1]+1);
+ else
+ $attributes[$name]=$this->parseTemplateProperty($value,$match[2][1]);
+ }
+ else
+ {
+ if($value[0]==='\'' || $value[0]==='"')
+ $attributes[$name]=$this->parseAttribute(substr($value,1,strlen($value)-2));
+ else
+ $attributes[$name]=$this->parseAttribute($value);
+ }
+ }
+ return $attributes;
+ }
+
+ protected function parseTemplateProperty($content,$offset)
+ {
+ $line=$this->_startingLine+count(explode("\n",substr($this->_content,0,$offset)))-1;
+ return array(self::CONFIG_TEMPLATE,new TTemplate($content,$this->_contextPath,$this->_tplFile,$line,false));
+ }
+
+ /**
+ * Parses a single attribute.
+ * @param string the string to be parsed.
+ * @return array attribute initialization
+ */
+ protected function parseAttribute($value)
+ {
+ if(($n=preg_match_all('/<%[#=].*?%>/msS',$value,$matches,PREG_OFFSET_CAPTURE))>0)
+ {
+ $isDataBind=false;
+ $textStart=0;
+ $expr='';
+ for($i=0;$i<$n;++$i)
+ {
+ $match=$matches[0][$i];
+ $token=$match[0];
+ $offset=$match[1];
+ $length=strlen($token);
+ if($token[2]==='#')
+ $isDataBind=true;
+ if($offset>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$offset-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ $expr.='.('.substr($token,3,$length-5).')';
+ $textStart=$offset+$length;
+ }
+ $length=strlen($value);
+ if($length>$textStart)
+ $expr.=".'".strtr(substr($value,$textStart,$length-$textStart),array("'"=>"\\'","\\"=>"\\\\"))."'";
+ if($isDataBind)
+ return array(self::CONFIG_DATABIND,ltrim($expr,'.'));
+ else
+ return array(self::CONFIG_EXPRESSION,ltrim($expr,'.'));
+ }
+ else if(preg_match('/\\s*(<%~.*?%>|<%\\$.*?%>|<%\\[.*?\\]%>|<%\/.*?%>)\\s*/msS',$value,$matches) && $matches[0]===$value)
+ {
+ $value=$matches[1];
+ if($value[2]==='~')
+ return array(self::CONFIG_ASSET,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='[')
+ return array(self::CONFIG_LOCALIZATION,trim(substr($value,3,strlen($value)-6)));
+ elseif($value[2]==='$')
+ return array(self::CONFIG_PARAMETER,trim(substr($value,3,strlen($value)-5)));
+ elseif($value[2]==='/') {
+ $literal = trim(substr($value,3,strlen($value)-5));
+ return array(self::CONFIG_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'");
+ }
+ }
+ else
+ return $value;
+ }
+
+ protected function validateAttributes($type,$attributes)
+ {
+ Prado::using($type);
+ if(($pos=strrpos($type,'.'))!==false)
+ $className=substr($type,$pos+1);
+ else
+ $className=$type;
+ $class=new ReflectionClass($className);
+ if(is_subclass_of($className,'TControl') || $className==='TControl')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ // a subproperty, so the first segment must be readable
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ {
+ // an event
+ if(!$class->hasMethod($name))
+ throw new TConfigurationException('template_event_unknown',$type,$name);
+ else if(!is_string($att))
+ throw new TConfigurationException('template_eventhandler_invalid',$type,$name);
+ }
+ else
+ {
+ // a simple property
+ if (! ($class->hasMethod('set'.$name) || $class->hasMethod('setjs'.$name)) )
+ {
+ if ($class->hasMethod('get'.$name) || $class->hasMethod('getjs'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ else if(is_array($att) && $att[0]!==self::CONFIG_EXPRESSION)
+ {
+ if(strcasecmp($name,'id')===0)
+ throw new TConfigurationException('template_controlid_invalid',$type);
+ else if(strcasecmp($name,'skinid')===0)
+ throw new TConfigurationException('template_controlskinid_invalid',$type);
+ }
+ }
+ }
+ }
+ else if(is_subclass_of($className,'TComponent') || $className==='TComponent')
+ {
+ foreach($attributes as $name=>$att)
+ {
+ if(is_array($att) && ($att[0]===self::CONFIG_DATABIND))
+ throw new TConfigurationException('template_databind_forbidden',$type,$name);
+ if(($pos=strpos($name,'.'))!==false)
+ {
+ // a subproperty, so the first segment must be readable
+ $subname=substr($name,0,$pos);
+ if(!$class->hasMethod('get'.$subname))
+ throw new TConfigurationException('template_property_unknown',$type,$subname);
+ }
+ else if(strncasecmp($name,'on',2)===0)
+ throw new TConfigurationException('template_event_forbidden',$type,$name);
+ else
+ {
+ // id is still alowed for TComponent, even if id property doesn't exist
+ if(strcasecmp($name,'id')!==0 && !$class->hasMethod('set'.$name))
+ {
+ if($class->hasMethod('get'.$name))
+ throw new TConfigurationException('template_property_readonly',$type,$name);
+ else
+ throw new TConfigurationException('template_property_unknown',$type,$name);
+ }
+ }
+ }
+ }
+ else
+ throw new TConfigurationException('template_component_required',$type);
+ }
+
+ /**
+ * @return array list of included external template files
+ */
+ public function getIncludedFiles()
+ {
+ return $this->_includedFiles;
+ }
+
+ /**
+ * Handles template parsing exception.
+ * This method rethrows the exception caught during template parsing.
+ * It adjusts the error location by giving out correct error line number and source file.
+ * @param Exception template exception
+ * @param int line number
+ * @param string template string if no source file is used
+ */
+ protected function handleException($e,$line,$input=null)
+ {
+ $srcFile=$this->_tplFile;
+
+ if(($n=count($this->_includedFiles))>0) // need to adjust error row number and file name
+ {
+ for($i=$n-1;$i>=0;--$i)
+ {
+ if($this->_includeAtLine[$i]<=$line)
+ {
+ if($line<$this->_includeAtLine[$i]+$this->_includeLines[$i])
+ {
+ $line=$line-$this->_includeAtLine[$i]+1;
+ $srcFile=$this->_includedFiles[$i];
+ break;
+ }
+ else
+ $line=$line-$this->_includeLines[$i]+1;
+ }
+ }
+ }
+ $exception=new TTemplateException('template_format_invalid',$e->getMessage());
+ $exception->setLineNumber($line);
+ if(!empty($srcFile))
+ $exception->setTemplateFile($srcFile);
+ else
+ $exception->setTemplateSource($input);
+ throw $exception;
+ }
+
+ /**
+ * Preprocesses the template string by including external templates
+ * @param string template string
+ * @return string expanded template string
+ */
+ protected function preprocess($input)
+ {
+ if($n=preg_match_all('/<%include(.*?)%>/',$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE))
+ {
+ for($i=0;$i<$n;++$i)
+ {
+ $filePath=Prado::getPathOfNamespace(trim($matches[$i][1][0]),TTemplateManager::TEMPLATE_FILE_EXT);
+ if($filePath!==null && is_file($filePath))
+ $this->_includedFiles[]=$filePath;
+ else
+ {
+ $errorLine=count(explode("\n",substr($input,0,$matches[$i][0][1]+1)));
+ $this->handleException(new TConfigurationException('template_include_invalid',trim($matches[$i][1][0])),$errorLine,$input);
+ }
+ }
+ $base=0;
+ for($i=0;$i<$n;++$i)
+ {
+ $ext=file_get_contents($this->_includedFiles[$i]);
+ $length=strlen($matches[$i][0][0]);
+ $offset=$base+$matches[$i][0][1];
+ $this->_includeAtLine[$i]=count(explode("\n",substr($input,0,$offset)));
+ $this->_includeLines[$i]=count(explode("\n",$ext));
+ $input=substr_replace($input,$ext,$offset,$length);
+ $base+=strlen($ext)-$length;
+ }
+ }
+
+ return $input;
+ }
+}
+
diff --git a/framework/Web/UI/TThemeManager.php b/framework/Web/UI/TThemeManager.php
index 57ab21ad..0d6befd4 100644
--- a/framework/Web/UI/TThemeManager.php
+++ b/framework/Web/UI/TThemeManager.php
@@ -1,517 +1,517 @@
-<?php
-/**
- * TThemeManager class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-Prado::using('System.Web.Services.TPageService');
-
-/**
- * TThemeManager class
- *
- * TThemeManager manages the themes used in a Prado application.
- *
- * Themes are stored under the directory specified by the
- * {@link setBasePath BasePath} property. The themes can be accessed
- * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory
- * and all the files under that directory. The name of a theme is the name
- * of the corresponding subdirectory.
- * By default, the base path of all themes is a directory named "themes"
- * under the directory containing the application entry script.
- * To get a theme (normally you do not need to), call {@link getTheme}.
- *
- * TThemeManager may be configured within page service tag in application
- * configuration file as follows,
- * <module id="themes" class="System.Web.UI.TThemeManager"
- * BasePath="Application.themes" BaseUrl="/themes" />
- * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
- * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TThemeManager extends TModule
-{
- /**
- * default themes base path
- */
- const DEFAULT_BASEPATH='themes';
-
- /**
- * default theme class
- */
- const DEFAULT_THEMECLASS = 'TTheme';
-
- /**
- * @var string
- */
- private $_themeClass=self::DEFAULT_THEMECLASS;
-
- /**
- * @var boolean whether this module has been initialized
- */
- private $_initialized=false;
- /**
- * @var string the directory containing all themes
- */
- private $_basePath=null;
- /**
- * @var string the base URL for all themes
- */
- private $_baseUrl=null;
-
- /**
- * Initializes the module.
- * This method is required by IModule and is invoked by application.
- * @param TXmlElement module configuration
- */
- public function init($config)
- {
- $this->_initialized=true;
- $service=$this->getService();
- if($service instanceof TPageService)
- $service->setThemeManager($this);
- else
- throw new TConfigurationException('thememanager_service_unavailable');
- }
-
- /**
- * @param string name of the theme to be retrieved
- * @return TTheme the theme retrieved
- */
- public function getTheme($name)
- {
- $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
- $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
- return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
- }
-
- /**
- * @param string|null $class Theme class name in namespace format
- */
- public function setThemeClass($class) {
- $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
- }
-
- /**
- * @return string Theme class name in namespace format. Defaults to {@link TThemeManager::DEFAULT_THEMECLASS DEFAULT_THEMECLASS}.
- */
- public function getThemeClass() {
- return $this->_themeClass;
- }
-
- /**
- * @return array list of available theme names
- */
- public function getAvailableThemes()
- {
- $themes=array();
- $basePath=$this->getBasePath();
- $folder=@opendir($basePath);
- while($file=@readdir($folder))
- {
- if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
- $themes[]=$file;
- }
- closedir($folder);
- return $themes;
- }
-
- /**
- * @return string the base path for all themes. It is returned as an absolute path.
- * @throws TConfigurationException if base path is not set and "themes" directory does not exist.
- */
- public function getBasePath()
- {
- if($this->_basePath===null)
- {
- $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
- if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
- throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
- $this->_basePath=$basePath;
- }
- return $this->_basePath;
- }
-
- /**
- * @param string the base path for all themes. It must be in the format of a namespace.
- * @throws TInvalidDataValueException if the base path is not a proper namespace.
- */
- public function setBasePath($value)
- {
- if($this->_initialized)
- throw new TInvalidOperationException('thememanager_basepath_unchangeable');
- else
- {
- $this->_basePath=Prado::getPathOfNamespace($value);
- if($this->_basePath===null || !is_dir($this->_basePath))
- throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
- }
- }
-
- /**
- * @return string the base URL for all themes.
- * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado.
- */
- public function getBaseUrl()
- {
- if($this->_baseUrl===null)
- {
- $appPath=dirname($this->getRequest()->getApplicationFilePath());
- $basePath=$this->getBasePath();
- if(strpos($basePath,$appPath)===false)
- throw new TConfigurationException('thememanager_baseurl_required');
- $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
- $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
- }
- return $this->_baseUrl;
- }
-
- /**
- * @param string the base URL for all themes.
- */
- public function setBaseUrl($value)
- {
- $this->_baseUrl=rtrim($value,'/');
- }
-}
-
-/**
- * TTheme class
- *
- * TTheme represents a particular theme. It is merely a collection of skins
- * that are applicable to the corresponding controls.
- *
- * Each theme is stored as a directory and files under that directory.
- * The theme name is the directory name. When TTheme is created, the files
- * whose name has the extension ".skin" are parsed and saved as controls skins.
- *
- * A skin is essentially a list of initial property values that are to be applied
- * to a control when the skin is applied.
- * Each type of control can have multiple skins identified by the SkinID.
- * If a skin does not have SkinID, it is the default skin that will be applied
- * to controls that do not specify particular SkinID.
- *
- * Whenever possible, TTheme will try to make use of available cache to save
- * the parsing time.
- *
- * To apply a theme to a particular control, call {@link applySkin}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class TTheme extends TApplicationComponent implements ITheme
-{
- /**
- * prefix for cache variable name used to store parsed themes
- */
- const THEME_CACHE_PREFIX='prado:theme:';
- /**
- * Extension name of skin files
- */
- const SKIN_FILE_EXT='.skin';
- /**
- * @var string theme path
- */
- private $_themePath;
- /**
- * @var string theme url
- */
- private $_themeUrl;
- /**
- * @var array list of skins for the theme
- */
- private $_skins=null;
- /**
- * @var string theme name
- */
- private $_name='';
- /**
- * @var array list of css files
- */
- private $_cssFiles=array();
- /**
- * @var array list of js files
- */
- private $_jsFiles=array();
-
- /**
- * Constructor.
- * @param string theme path
- * @param string theme URL
- * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
- */
- public function __construct($themePath,$themeUrl)
- {
- $this->_themeUrl=$themeUrl;
- $this->_themePath=realpath($themePath);
- $this->_name=basename($themePath);
- $cacheValid=false;
- // TODO: the following needs to be cleaned up (Qiang)
- if(($cache=$this->getApplication()->getCache())!==null)
- {
- $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
- if(is_array($array))
- {
- list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
- if($this->getApplication()->getMode()!==TApplicationMode::Performance)
- {
- if(($dir=opendir($themePath))===false)
- throw new TIOException('theme_path_inexistent',$themePath);
- $cacheValid=true;
- while(($file=readdir($dir))!==false)
- {
- if($file==='.' || $file==='..')
- continue;
- else if(basename($file,'.css')!==$file)
- $this->_cssFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,'.js')!==$file)
- $this->_jsFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
- {
- $cacheValid=false;
- break;
- }
- }
- closedir($dir);
- if($cacheValid)
- $this->_skins=$skins;
- }
- else
- {
- $cacheValid=true;
- $this->_cssFiles=$cssFiles;
- $this->_jsFiles=$jsFiles;
- $this->_skins=$skins;
- }
- }
- }
- if(!$cacheValid)
- {
- $this->_cssFiles=array();
- $this->_jsFiles=array();
- $this->_skins=array();
- if(($dir=opendir($themePath))===false)
- throw new TIOException('theme_path_inexistent',$themePath);
- while(($file=readdir($dir))!==false)
- {
- if($file==='.' || $file==='..')
- continue;
- else if(basename($file,'.css')!==$file)
- $this->_cssFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,'.js')!==$file)
- $this->_jsFiles[]=$themeUrl.'/'.$file;
- else if(basename($file,self::SKIN_FILE_EXT)!==$file)
- {
- $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
- foreach($template->getItems() as $skin)
- {
- if(!isset($skin[2])) // a text string, ignored
- continue;
- else if($skin[0]!==-1)
- throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
- $type=$skin[1];
- $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
- unset($skin[2]['skinid']);
- if(isset($this->_skins[$type][$id]))
- throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
- /*
- foreach($skin[2] as $name=>$value)
- {
- if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER))
- throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
- }
- */
- $this->_skins[$type][$id]=$skin[2];
- }
- }
- }
- closedir($dir);
- sort($this->_cssFiles);
- sort($this->_jsFiles);
- if($cache!==null)
- $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
- }
- }
-
- /**
- * @return string theme name
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string theme name
- */
- protected function setName($value)
- {
- $this->_name = $value;
- }
-
- /**
- * @return string the URL to the theme folder (without ending slash)
- */
- public function getBaseUrl()
- {
- return $this->_themeUrl;
- }
-
- /**
- * @param string the URL to the theme folder
- */
- protected function setBaseUrl($value)
- {
- $this->_themeUrl=rtrim($value,'/');
- }
-
- /**
- * @return string the file path to the theme folder
- */
- public function getBasePath()
- {
- return $this->_themePath;
- }
-
- /**
- * @param string tthe file path to the theme folder
- */
- protected function setBasePath($value)
- {
- $this->_themePath=$value;
- }
-
- /**
- * @return array list of skins for the theme
- */
- public function getSkins()
- {
- return $this->_skins;
- }
-
- /**
- * @param array list of skins for the theme
- */
- protected function setSkins($value)
- {
- $this->_skins = $value;
- }
-
- /**
- * Applies the theme to a particular control.
- * The control's class name and SkinID value will be used to
- * identify which skin to be applied. If the control's SkinID is empty,
- * the default skin will be applied.
- * @param TControl the control to be applied with a skin
- * @return boolean if a skin is successfully applied
- * @throws TConfigurationException if any error happened during the skin application
- */
- public function applySkin($control)
- {
- $type=get_class($control);
- if(($id=$control->getSkinID())==='')
- $id=0;
- if(isset($this->_skins[$type][$id]))
- {
- foreach($this->_skins[$type][$id] as $name=>$value)
- {
- Prado::trace("Applying skin $name to $type",'System.Web.UI.TThemeManager');
- if(is_array($value))
- {
- switch($value[0])
- {
- case TTemplate::CONFIG_EXPRESSION:
- $value=$this->evaluateExpression($value[1]);
- break;
- case TTemplate::CONFIG_ASSET:
- $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
- break;
- case TTemplate::CONFIG_DATABIND:
- $control->bindProperty($name,$value[1]);
- break;
- case TTemplate::CONFIG_PARAMETER:
- $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
- break;
- case TTemplate::CONFIG_TEMPLATE:
- $control->setSubProperty($name,$value[1]);
- break;
- case TTemplate::CONFIG_LOCALIZATION:
- $control->setSubProperty($name,Prado::localize($value[1]));
- break;
- default:
- throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
- break;
- }
- }
- if(!is_array($value))
- {
- if(strpos($name,'.')===false) // is simple property or custom attribute
- {
- if($control->hasProperty($name))
- {
- if($control->canSetProperty($name))
- {
- $setter='set'.$name;
- $control->$setter($value);
- }
- else
- throw new TConfigurationException('theme_property_readonly',$type,$name);
- }
- else
- throw new TConfigurationException('theme_property_undefined',$type,$name);
- }
- else // complex property
- $control->setSubProperty($name,$value);
- }
- }
- return true;
- }
- else
- return false;
- }
-
- /**
- * @return array list of CSS files (URL) in the theme
- */
- public function getStyleSheetFiles()
- {
- return $this->_cssFiles;
- }
-
- /**
- * @param array list of CSS files (URL) in the theme
- */
- protected function setStyleSheetFiles($value)
- {
- $this->_cssFiles=$value;
- }
-
- /**
- * @return array list of Javascript files (URL) in the theme
- */
- public function getJavaScriptFiles()
- {
- return $this->_jsFiles;
- }
-
- /**
- * @param array list of Javascript files (URL) in the theme
- */
- protected function setJavaScriptFiles($value)
- {
- $this->_jsFiles=$value;
- }
-}
-
-?>
+<?php
+/**
+ * TThemeManager class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+Prado::using('System.Web.Services.TPageService');
+
+/**
+ * TThemeManager class
+ *
+ * TThemeManager manages the themes used in a Prado application.
+ *
+ * Themes are stored under the directory specified by the
+ * {@link setBasePath BasePath} property. The themes can be accessed
+ * via URL {@link setBaseUrl BaseUrl}. Each theme is represented by a subdirectory
+ * and all the files under that directory. The name of a theme is the name
+ * of the corresponding subdirectory.
+ * By default, the base path of all themes is a directory named "themes"
+ * under the directory containing the application entry script.
+ * To get a theme (normally you do not need to), call {@link getTheme}.
+ *
+ * TThemeManager may be configured within page service tag in application
+ * configuration file as follows,
+ * <module id="themes" class="System.Web.UI.TThemeManager"
+ * BasePath="Application.themes" BaseUrl="/themes" />
+ * where {@link getCacheExpire CacheExpire}, {@link getCacheControl CacheControl}
+ * and {@link getBufferOutput BufferOutput} are configurable properties of THttpResponse.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TThemeManager extends TModule
+{
+ /**
+ * default themes base path
+ */
+ const DEFAULT_BASEPATH='themes';
+
+ /**
+ * default theme class
+ */
+ const DEFAULT_THEMECLASS = 'TTheme';
+
+ /**
+ * @var string
+ */
+ private $_themeClass=self::DEFAULT_THEMECLASS;
+
+ /**
+ * @var boolean whether this module has been initialized
+ */
+ private $_initialized=false;
+ /**
+ * @var string the directory containing all themes
+ */
+ private $_basePath=null;
+ /**
+ * @var string the base URL for all themes
+ */
+ private $_baseUrl=null;
+
+ /**
+ * Initializes the module.
+ * This method is required by IModule and is invoked by application.
+ * @param TXmlElement module configuration
+ */
+ public function init($config)
+ {
+ $this->_initialized=true;
+ $service=$this->getService();
+ if($service instanceof TPageService)
+ $service->setThemeManager($this);
+ else
+ throw new TConfigurationException('thememanager_service_unavailable');
+ }
+
+ /**
+ * @param string name of the theme to be retrieved
+ * @return TTheme the theme retrieved
+ */
+ public function getTheme($name)
+ {
+ $themePath=$this->getBasePath().DIRECTORY_SEPARATOR.$name;
+ $themeUrl=rtrim($this->getBaseUrl(),'/').'/'.$name;
+ return Prado::createComponent($this->getThemeClass(), $themePath, $themeUrl);
+ }
+
+ /**
+ * @param string|null $class Theme class name in namespace format
+ */
+ public function setThemeClass($class) {
+ $this->_themeClass = $class===null ? self::DEFAULT_THEMECLASS : (string)$class;
+ }
+
+ /**
+ * @return string Theme class name in namespace format. Defaults to {@link TThemeManager::DEFAULT_THEMECLASS DEFAULT_THEMECLASS}.
+ */
+ public function getThemeClass() {
+ return $this->_themeClass;
+ }
+
+ /**
+ * @return array list of available theme names
+ */
+ public function getAvailableThemes()
+ {
+ $themes=array();
+ $basePath=$this->getBasePath();
+ $folder=@opendir($basePath);
+ while($file=@readdir($folder))
+ {
+ if($file!=='.' && $file!=='..' && $file!=='.svn' && is_dir($basePath.DIRECTORY_SEPARATOR.$file))
+ $themes[]=$file;
+ }
+ closedir($folder);
+ return $themes;
+ }
+
+ /**
+ * @return string the base path for all themes. It is returned as an absolute path.
+ * @throws TConfigurationException if base path is not set and "themes" directory does not exist.
+ */
+ public function getBasePath()
+ {
+ if($this->_basePath===null)
+ {
+ $this->_basePath=dirname($this->getRequest()->getApplicationFilePath()).DIRECTORY_SEPARATOR.self::DEFAULT_BASEPATH;
+ if(($basePath=realpath($this->_basePath))===false || !is_dir($basePath))
+ throw new TConfigurationException('thememanager_basepath_invalid2',$this->_basePath);
+ $this->_basePath=$basePath;
+ }
+ return $this->_basePath;
+ }
+
+ /**
+ * @param string the base path for all themes. It must be in the format of a namespace.
+ * @throws TInvalidDataValueException if the base path is not a proper namespace.
+ */
+ public function setBasePath($value)
+ {
+ if($this->_initialized)
+ throw new TInvalidOperationException('thememanager_basepath_unchangeable');
+ else
+ {
+ $this->_basePath=Prado::getPathOfNamespace($value);
+ if($this->_basePath===null || !is_dir($this->_basePath))
+ throw new TInvalidDataValueException('thememanager_basepath_invalid',$value);
+ }
+ }
+
+ /**
+ * @return string the base URL for all themes.
+ * @throws TConfigurationException If base URL is not set and a correct one cannot be determined by Prado.
+ */
+ public function getBaseUrl()
+ {
+ if($this->_baseUrl===null)
+ {
+ $appPath=dirname($this->getRequest()->getApplicationFilePath());
+ $basePath=$this->getBasePath();
+ if(strpos($basePath,$appPath)===false)
+ throw new TConfigurationException('thememanager_baseurl_required');
+ $appUrl=rtrim(dirname($this->getRequest()->getApplicationUrl()),'/\\');
+ $this->_baseUrl=$appUrl.strtr(substr($basePath,strlen($appPath)),'\\','/');
+ }
+ return $this->_baseUrl;
+ }
+
+ /**
+ * @param string the base URL for all themes.
+ */
+ public function setBaseUrl($value)
+ {
+ $this->_baseUrl=rtrim($value,'/');
+ }
+}
+
+/**
+ * TTheme class
+ *
+ * TTheme represents a particular theme. It is merely a collection of skins
+ * that are applicable to the corresponding controls.
+ *
+ * Each theme is stored as a directory and files under that directory.
+ * The theme name is the directory name. When TTheme is created, the files
+ * whose name has the extension ".skin" are parsed and saved as controls skins.
+ *
+ * A skin is essentially a list of initial property values that are to be applied
+ * to a control when the skin is applied.
+ * Each type of control can have multiple skins identified by the SkinID.
+ * If a skin does not have SkinID, it is the default skin that will be applied
+ * to controls that do not specify particular SkinID.
+ *
+ * Whenever possible, TTheme will try to make use of available cache to save
+ * the parsing time.
+ *
+ * To apply a theme to a particular control, call {@link applySkin}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class TTheme extends TApplicationComponent implements ITheme
+{
+ /**
+ * prefix for cache variable name used to store parsed themes
+ */
+ const THEME_CACHE_PREFIX='prado:theme:';
+ /**
+ * Extension name of skin files
+ */
+ const SKIN_FILE_EXT='.skin';
+ /**
+ * @var string theme path
+ */
+ private $_themePath;
+ /**
+ * @var string theme url
+ */
+ private $_themeUrl;
+ /**
+ * @var array list of skins for the theme
+ */
+ private $_skins=null;
+ /**
+ * @var string theme name
+ */
+ private $_name='';
+ /**
+ * @var array list of css files
+ */
+ private $_cssFiles=array();
+ /**
+ * @var array list of js files
+ */
+ private $_jsFiles=array();
+
+ /**
+ * Constructor.
+ * @param string theme path
+ * @param string theme URL
+ * @throws TConfigurationException if theme path does not exist or any parsing error of the skin files
+ */
+ public function __construct($themePath,$themeUrl)
+ {
+ $this->_themeUrl=$themeUrl;
+ $this->_themePath=realpath($themePath);
+ $this->_name=basename($themePath);
+ $cacheValid=false;
+ // TODO: the following needs to be cleaned up (Qiang)
+ if(($cache=$this->getApplication()->getCache())!==null)
+ {
+ $array=$cache->get(self::THEME_CACHE_PREFIX.$themePath);
+ if(is_array($array))
+ {
+ list($skins,$cssFiles,$jsFiles,$timestamp)=$array;
+ if($this->getApplication()->getMode()!==TApplicationMode::Performance)
+ {
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ $cacheValid=true;
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file && filemtime($themePath.DIRECTORY_SEPARATOR.$file)>$timestamp)
+ {
+ $cacheValid=false;
+ break;
+ }
+ }
+ closedir($dir);
+ if($cacheValid)
+ $this->_skins=$skins;
+ }
+ else
+ {
+ $cacheValid=true;
+ $this->_cssFiles=$cssFiles;
+ $this->_jsFiles=$jsFiles;
+ $this->_skins=$skins;
+ }
+ }
+ }
+ if(!$cacheValid)
+ {
+ $this->_cssFiles=array();
+ $this->_jsFiles=array();
+ $this->_skins=array();
+ if(($dir=opendir($themePath))===false)
+ throw new TIOException('theme_path_inexistent',$themePath);
+ while(($file=readdir($dir))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ else if(basename($file,'.css')!==$file)
+ $this->_cssFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,'.js')!==$file)
+ $this->_jsFiles[]=$themeUrl.'/'.$file;
+ else if(basename($file,self::SKIN_FILE_EXT)!==$file)
+ {
+ $template=new TTemplate(file_get_contents($themePath.'/'.$file),$themePath,$themePath.'/'.$file);
+ foreach($template->getItems() as $skin)
+ {
+ if(!isset($skin[2])) // a text string, ignored
+ continue;
+ else if($skin[0]!==-1)
+ throw new TConfigurationException('theme_control_nested',$skin[1],dirname($themePath));
+ $type=$skin[1];
+ $id=isset($skin[2]['skinid'])?$skin[2]['skinid']:0;
+ unset($skin[2]['skinid']);
+ if(isset($this->_skins[$type][$id]))
+ throw new TConfigurationException('theme_skinid_duplicated',$type,$id,dirname($themePath));
+ /*
+ foreach($skin[2] as $name=>$value)
+ {
+ if(is_array($value) && ($value[0]===TTemplate::CONFIG_DATABIND || $value[0]===TTemplate::CONFIG_PARAMETER))
+ throw new TConfigurationException('theme_databind_forbidden',dirname($themePath),$type,$id);
+ }
+ */
+ $this->_skins[$type][$id]=$skin[2];
+ }
+ }
+ }
+ closedir($dir);
+ sort($this->_cssFiles);
+ sort($this->_jsFiles);
+ if($cache!==null)
+ $cache->set(self::THEME_CACHE_PREFIX.$themePath,array($this->_skins,$this->_cssFiles,$this->_jsFiles,time()));
+ }
+ }
+
+ /**
+ * @return string theme name
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string theme name
+ */
+ protected function setName($value)
+ {
+ $this->_name = $value;
+ }
+
+ /**
+ * @return string the URL to the theme folder (without ending slash)
+ */
+ public function getBaseUrl()
+ {
+ return $this->_themeUrl;
+ }
+
+ /**
+ * @param string the URL to the theme folder
+ */
+ protected function setBaseUrl($value)
+ {
+ $this->_themeUrl=rtrim($value,'/');
+ }
+
+ /**
+ * @return string the file path to the theme folder
+ */
+ public function getBasePath()
+ {
+ return $this->_themePath;
+ }
+
+ /**
+ * @param string tthe file path to the theme folder
+ */
+ protected function setBasePath($value)
+ {
+ $this->_themePath=$value;
+ }
+
+ /**
+ * @return array list of skins for the theme
+ */
+ public function getSkins()
+ {
+ return $this->_skins;
+ }
+
+ /**
+ * @param array list of skins for the theme
+ */
+ protected function setSkins($value)
+ {
+ $this->_skins = $value;
+ }
+
+ /**
+ * Applies the theme to a particular control.
+ * The control's class name and SkinID value will be used to
+ * identify which skin to be applied. If the control's SkinID is empty,
+ * the default skin will be applied.
+ * @param TControl the control to be applied with a skin
+ * @return boolean if a skin is successfully applied
+ * @throws TConfigurationException if any error happened during the skin application
+ */
+ public function applySkin($control)
+ {
+ $type=get_class($control);
+ if(($id=$control->getSkinID())==='')
+ $id=0;
+ if(isset($this->_skins[$type][$id]))
+ {
+ foreach($this->_skins[$type][$id] as $name=>$value)
+ {
+ Prado::trace("Applying skin $name to $type",'System.Web.UI.TThemeManager');
+ if(is_array($value))
+ {
+ switch($value[0])
+ {
+ case TTemplate::CONFIG_EXPRESSION:
+ $value=$this->evaluateExpression($value[1]);
+ break;
+ case TTemplate::CONFIG_ASSET:
+ $value=$this->_themeUrl.'/'.ltrim($value[1],'/');
+ break;
+ case TTemplate::CONFIG_DATABIND:
+ $control->bindProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_PARAMETER:
+ $control->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1]));
+ break;
+ case TTemplate::CONFIG_TEMPLATE:
+ $control->setSubProperty($name,$value[1]);
+ break;
+ case TTemplate::CONFIG_LOCALIZATION:
+ $control->setSubProperty($name,Prado::localize($value[1]));
+ break;
+ default:
+ throw new TConfigurationException('theme_tag_unexpected',$name,$value[0]);
+ break;
+ }
+ }
+ if(!is_array($value))
+ {
+ if(strpos($name,'.')===false) // is simple property or custom attribute
+ {
+ if($control->hasProperty($name))
+ {
+ if($control->canSetProperty($name))
+ {
+ $setter='set'.$name;
+ $control->$setter($value);
+ }
+ else
+ throw new TConfigurationException('theme_property_readonly',$type,$name);
+ }
+ else
+ throw new TConfigurationException('theme_property_undefined',$type,$name);
+ }
+ else // complex property
+ $control->setSubProperty($name,$value);
+ }
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @return array list of CSS files (URL) in the theme
+ */
+ public function getStyleSheetFiles()
+ {
+ return $this->_cssFiles;
+ }
+
+ /**
+ * @param array list of CSS files (URL) in the theme
+ */
+ protected function setStyleSheetFiles($value)
+ {
+ $this->_cssFiles=$value;
+ }
+
+ /**
+ * @return array list of Javascript files (URL) in the theme
+ */
+ public function getJavaScriptFiles()
+ {
+ return $this->_jsFiles;
+ }
+
+ /**
+ * @param array list of Javascript files (URL) in the theme
+ */
+ protected function setJavaScriptFiles($value)
+ {
+ $this->_jsFiles=$value;
+ }
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TAccordion.php b/framework/Web/UI/WebControls/TAccordion.php
index 22ff6b71..bfe3451d 100644
--- a/framework/Web/UI/WebControls/TAccordion.php
+++ b/framework/Web/UI/WebControls/TAccordion.php
@@ -1,744 +1,744 @@
-<?php
-/**
- * TAccordion class file.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-
-/**
- * Class TAccordion.
- *
- * TAccordion displays an accordion control. Users can click on the view headers to switch among
- * different accordion views. Each accordion view is an independent panel that can contain arbitrary content.
- *
- * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible
- * accordion views. At any time, only one accordion view is visible (active), which is specified by any of
- * the following properties:
- * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
- * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
- * - {@link setActiveView ActiveView} - the visible view instance.
- * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
- * are set, the latter takes precedence.
- *
- * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default,
- * an embedded CSS file will be published which contains the default CSS for TTabPanel.
- * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
- * The following properties specify the CSS classes used for elements in a TAccordion:
- * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion');
- * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header');
- * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active');
- * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view');
- *
- * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated.
- * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds;
- * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation.
- *
- * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling.
- * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property.
- * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion
- *
- * To use TAccordion, write a template like following:
- * <code>
- * <com:TAccordion>
- * <com:TAccordionView Caption="View 1">
- * content for view 1
- * </com:TAccordionView>
- * <com:TAccordionView Caption="View 2">
- * content for view 2
- * </com:TAccordionView>
- * <com:TAccordionView Caption="View 3">
- * content for view 3
- * </com:TAccordionView>
- * </com:TAccordion>
- * </code>
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-
-class TAccordion extends TWebControl implements IPostBackDataHandler
-{
- private $_dataChanged=false;
-
- /**
- * @return string tag name for the control
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TAccordionView} objects into the {@link getViews Views} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TAccordionView)
- $this->getControls()->add($object);
- }
-
- /**
- * Returns the index of the active accordion view.
- * Note, this property may not return the correct index.
- * To ensure the correctness, call {@link getActiveView()} first.
- * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active).
- */
- public function getActiveViewIndex()
- {
- return $this->getViewState('ActiveViewIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
- * @throws TInvalidDataValueException if the view index is invalid
- */
- public function setActiveViewIndex($value)
- {
- $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * Returns the ID of the active accordion view.
- * Note, this property may not return the correct ID.
- * To ensure the correctness, call {@link getActiveView()} first.
- * @return string The ID of the active accordion view. Defaults to '', meaning not set.
- */
- public function getActiveViewID()
- {
- return $this->getViewState('ActiveViewID','');
- }
-
- /**
- * @param string The ID of the active accordion view.
- */
- public function setActiveViewID($value)
- {
- $this->setViewState('ActiveViewID',$value,'');
- }
-
- /**
- * Returns the currently active view.
- * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
- * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
- * @return TAccordionView the currently active view, null if no active view
- * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
- */
- public function getActiveView()
- {
- $activeView=null;
- $views=$this->getViews();
- if(($id=$this->getActiveViewID())!=='')
- {
- if(($index=$views->findIndexByID($id))>=0)
- $activeView=$views->itemAt($index);
- else
- throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
- }
- else if(($index=$this->getActiveViewIndex())>=0)
- {
- if($index<$views->getCount())
- $activeView=$views->itemAt($index);
- else
- throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
- }
- else
- {
- foreach($views as $index=>$view)
- {
- if($view->getActive())
- {
- $activeView=$view;
- break;
- }
- }
- }
- if($activeView!==null)
- $this->activateView($activeView);
- return $activeView;
- }
-
- /**
- * @param TAccordionView the view to be activated
- * @throws TInvalidOperationException if the view is not in the view collection
- */
- public function setActiveView($view)
- {
- if($this->getViews()->indexOf($view)>=0)
- $this->activateView($view);
- else
- throw new TInvalidOperationException('tabpanel_view_inexistent');
- }
-
- /**
- * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl','default');
- }
-
- /**
- * @param string URL for the CSS file including all relevant CSS class definitions.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string CSS class for the whole accordion control div.
- */
- public function getCssClass()
- {
- $cssClass=parent::getCssClass();
- return $cssClass===''?'accordion':$cssClass;
- }
-
- /**
- * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
- */
- public function getViewCssClass()
- {
- return $this->getViewStyle()->getCssClass();
- }
-
- /**
- * @param string CSS class for the currently displayed view div.
- */
- public function setViewCssClass($value)
- {
- $this->getViewStyle()->setCssClass($value);
- }
-
- /**
- * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
- */
- public function getAnimationDuration()
- {
- return $this->getViewState('AnimationDuration','1');
- }
-
- /**
- * @param string CSS class for the currently displayed view div.
- */
- public function setAnimationDuration($value)
- {
- $this->setViewState('AnimationDuration',$value);
- }
-
- /**
- * @return TStyle the style for all the view div
- */
- public function getViewStyle()
- {
- if(($style=$this->getViewState('ViewStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-view');
- $this->setViewState('ViewStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string CSS class for view headers. Defaults to 'accordion-header'.
- */
- public function getHeaderCssClass()
- {
- return $this->getHeaderStyle()->getCssClass();
- }
-
- /**
- * @param string CSS class for view headers.
- */
- public function setHeaderCssClass($value)
- {
- $this->getHeaderStyle()->setCssClass($value);
- }
-
- /**
- * @return TStyle the style for all the inactive header div
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-header');
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'.
- */
- public function getActiveHeaderCssClass()
- {
- return $this->getActiveHeaderStyle()->getCssClass();
- }
-
- /**
- * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass.
- */
- public function setActiveHeaderCssClass($value)
- {
- $this->getActiveHeaderStyle()->setCssClass($value);
- }
-
- /**
- * @return TStyle the style for the active header div
- */
- public function getActiveHeaderStyle()
- {
- if(($style=$this->getViewState('ActiveHeaderStyle',null))===null)
- {
- $style=new TStyle;
- $style->setCssClass('accordion-header-active');
- $this->setViewState('ActiveHeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return integer Maximum height for the accordion views. If non specified, the accordion will auto-sized to the largest of all views, so it can encompass all of them without scrolling
- */
- public function getViewHeight()
- {
- return TPropertyValue::ensureInteger($this->getViewState('ViewHeight'));
- }
-
- /**
- * @param integer Maximum height for the accordion views. If any of the accordion's views' content is larger, those views will be made scrollable when activated
- */
- public function setViewHeight($value)
- {
- $this->setViewState('ViewHeight', TPropertyValue::ensureInteger($value));
- }
-
- /**
- * Activates the specified view.
- * If there is any other view currently active, it will be deactivated.
- * @param TAccordionView the view to be activated. If null, all views will be deactivated.
- */
- protected function activateView($view)
- {
- $this->setActiveViewIndex(-1);
- $this->setActiveViewID('');
- foreach($this->getViews() as $index=>$v)
- {
- if($view===$v)
- {
- $this->setActiveViewIndex($index);
- $this->setActiveViewID($view->getID(false));
- $view->setActive(true);
- }
- else
- $v->setActive(false);
- }
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if(($index=$values[$this->getClientID().'_1'])!==null)
- {
- $index=(int)$index;
- $currentIndex=$this->getActiveViewIndex();
- if($currentIndex!==$index)
- {
- $this->setActiveViewID(''); // clear up view ID
- $this->setActiveViewIndex($index);
- return $this->_dataChanged=true;
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- // do nothing
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->setCssClass($this->getCssClass());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->getActiveView(); // determine the active view
- $this->registerStyleSheet();
- }
-
- /**
- * Registers the CSS relevant to the TAccordion.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- $url = $this->getCssUrl();
-
- if($url === '') {
- return;
- }
-
- if($url === 'default') {
- $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css');
- }
-
- if($url !== '') {
- $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
- }
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $id=$this->getClientID();
- $options=TJavaScript::encode($this->getClientOptions());
- $className=$this->getClientClassName();
- $page=$this->getPage();
- $cs=$page->getClientScript();
- $cs->registerPradoScript('accordion');
- $code="new $className($options);";
- $cs->registerEndScript("prado:$id", $code);
- // ensure an item is always active and visible
- $index = $this->getActiveViewIndex();
- if(!$this->getViews()->itemAt($index)->Visible)
- $index=0;
- $cs->registerHiddenField($id.'_1', $index);
- $page->registerRequiresPostData($this);
- $page->registerRequiresPostData($id."_1");
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TAccordion';
- }
-
- /**
- * @return array the options for JavaScript
- */
- protected function getClientOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['ActiveHeaderCssClass'] = $this->getActiveHeaderCssClass();
- $options['HeaderCssClass'] = $this->getHeaderCssClass();
- $options['Duration'] = $this->getAnimationDuration();
-
- if (($viewheight = $this->getViewHeight())>0)
- $options['maxHeight'] = $viewheight;
- $views = array();
- foreach($this->getViews() as $view)
- $views[$view->getClientID()] = $view->getVisible() ? '1': '0';
- $options['Views'] = $views;
-
- return $options;
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TAccordionViewCollection control collection
- */
- protected function createControlCollection()
- {
- return new TAccordionViewCollection($this);
- }
-
- /**
- * @return TAccordionViewCollection list of {@link TAccordionView} controls
- */
- public function getViews()
- {
- return $this->getControls();
- }
-
- public function render($writer)
- {
- $this->registerClientScript();
- parent::render($writer);
- }
-
- /**
- * Renders body contents of the accordion control.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- $views=$this->getViews();
- if($views->getCount()>0)
- {
- $writer->writeLine();
- foreach($views as $view)
- {
- $view->renderHeader($writer);
- $view->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
-
-}
-
-/**
- * Class TAccordionView.
- *
- * TAccordionView represents a single view in a {@link TAccordion}.
- *
- * TAccordionView is represented inside the {@link TAccordion} with an header label whose text is defined by
- * the {@link setCaption Caption} property; optionally the label can be an hyperlink: use the
- * {@link setNavigateUrl NavigateUrl} property to define the destination url.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TAccordionView extends TWebControl
-{
- private $_active=false;
-
- /**
- * @return the tag name for the view element
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
- $this->getStyle()->setStyleField('display','none');
-
- $this->getStyle()->mergeWith($this->getParent()->getViewStyle());
-
- parent::addAttributesToRender($writer);
-
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * @return string the caption displayed on this header. Defaults to ''.
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string the caption displayed on this header
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL of the target page. Defaults to ''.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL of the target page.
- * If not empty, clicking on this header will redirect the browser to the specified URL.
- * @param string the URL of the target page.
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the text content displayed on this view. Defaults to ''.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content to be displayed on this view.
- * If this is not empty, the child content of the view will be ignored.
- * @param string the text content displayed on this view
- */
- public function setText($value)
- {
- $this->setViewState('Text',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return boolean whether this accordion view is active. Defaults to false.
- */
- public function getActive()
- {
- return $this->_active;
- }
-
- /**
- * @param boolean whether this accordion view is active.
- */
- public function setActive($value)
- {
- $this->_active=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Renders body contents of the accordion view.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())!=='')
- $writer->write($text);
- else if($this->getHasControls())
- parent::renderContents($writer);
- }
-
- /**
- * Renders the header associated with the accordion view.
- * @param THtmlWriter the writer for rendering purpose.
- */
- public function renderHeader($writer)
- {
- if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
- {
- $writer->addAttribute('id',$this->getClientID().'_0');
-
- $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle();
-
- $style->addAttributesToRender($writer);
-
- $writer->renderBeginTag($this->getTagName());
-
- $this->renderHeaderContent($writer);
-
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the content in the header.
- * By default, a hyperlink is displayed.
- * @param THtmlWriter the HTML writer
- */
- protected function renderHeaderContent($writer)
- {
- $url = $this->getNavigateUrl();
- if(($caption=$this->getCaption())==='')
- $caption='&nbsp;';
-
- if ($url!='')
- $writer->write("<a href=\"{$url}\">");
- $writer->write("{$caption}");
- if ($url!='')
- $writer->write("</a>");
- }
-}
-
-/**
- * Class TAccordionViewCollection.
- *
- * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TAccordionViewCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing sanity check on the type of new item.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TAccordionView} object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TAccordionView)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
- }
-
- /**
- * Finds the index of the accordion view whose ID is the same as the one being looked for.
- * @param string the explicit ID of the accordion view to be looked for
- * @return integer the index of the accordion view found, -1 if not found.
- */
- public function findIndexByID($id)
- {
- foreach($this as $index=>$view)
- {
- if($view->getID(false)===$id)
- return $index;
- }
- return -1;
- }
-}
-
-?>
+<?php
+/**
+ * TAccordion class file.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+/**
+ * Class TAccordion.
+ *
+ * TAccordion displays an accordion control. Users can click on the view headers to switch among
+ * different accordion views. Each accordion view is an independent panel that can contain arbitrary content.
+ *
+ * A TAccordion control consists of one or several {@link TAccordionView} controls representing the possible
+ * accordion views. At any time, only one accordion view is visible (active), which is specified by any of
+ * the following properties:
+ * - {@link setActiveViewIndex ActiveViewIndex} - the zero-based integer index of the view in the view collection.
+ * - {@link setActiveViewID ActiveViewID} - the text ID of the visible view.
+ * - {@link setActiveView ActiveView} - the visible view instance.
+ * If both {@link setActiveViewIndex ActiveViewIndex} and {@link setActiveViewID ActiveViewID}
+ * are set, the latter takes precedence.
+ *
+ * TAccordion uses CSS to specify the appearance of the accordion headers and panel. By default,
+ * an embedded CSS file will be published which contains the default CSS for TTabPanel.
+ * You may also use your own CSS file by specifying the {@link setCssUrl CssUrl} property.
+ * The following properties specify the CSS classes used for elements in a TAccordion:
+ * - {@link setCssClass CssClass} - the CSS class name for the outer-most div element (defaults to 'accordion');
+ * - {@link setHeaderCssClass HeaderCssClass} - the CSS class name for nonactive accordion div elements (defaults to 'accordion-header');
+ * - {@link setActiveHeaderCssClass ActiveHeaderCssClass} - the CSS class name for the active accordion div element (defaults to 'accordion-header-active');
+ * - {@link setViewCssClass ViewCssClass} - the CSS class for the div element enclosing view content (defaults to 'accordion-view');
+ *
+ * When the user clicks on a view header, the switch between the old visible view and the clicked one is animated.
+ * You can use the {@link setAnimationDuration AnimationDuration} property to set the animation length in seconds;
+ * it defaults to 1 second, and when set to 0 it will produce an immediate switch with no animation.
+ *
+ * The TAccordion auto-sizes itself to the largest of all views, so it can encompass all of them without scrolling.
+ * If you want to specify a fixed height (in pixels), use the {@link setViewHeight ViewHeight} property.
+ * When a TAccordion is nested inside another, it's adviced to manually specify a {@link setViewHeight ViewHeight} for the internal TAccordion
+ *
+ * To use TAccordion, write a template like following:
+ * <code>
+ * <com:TAccordion>
+ * <com:TAccordionView Caption="View 1">
+ * content for view 1
+ * </com:TAccordionView>
+ * <com:TAccordionView Caption="View 2">
+ * content for view 2
+ * </com:TAccordionView>
+ * <com:TAccordionView Caption="View 3">
+ * content for view 3
+ * </com:TAccordionView>
+ * </com:TAccordion>
+ * </code>
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+
+class TAccordion extends TWebControl implements IPostBackDataHandler
+{
+ private $_dataChanged=false;
+
+ /**
+ * @return string tag name for the control
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TAccordionView} objects into the {@link getViews Views} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TAccordionView)
+ $this->getControls()->add($object);
+ }
+
+ /**
+ * Returns the index of the active accordion view.
+ * Note, this property may not return the correct index.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return integer the zero-based index of the active accordion view. If -1, it means no active accordion view. Default is 0 (the first view is active).
+ */
+ public function getActiveViewIndex()
+ {
+ return $this->getViewState('ActiveViewIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ $this->setViewState('ActiveViewIndex',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * Returns the ID of the active accordion view.
+ * Note, this property may not return the correct ID.
+ * To ensure the correctness, call {@link getActiveView()} first.
+ * @return string The ID of the active accordion view. Defaults to '', meaning not set.
+ */
+ public function getActiveViewID()
+ {
+ return $this->getViewState('ActiveViewID','');
+ }
+
+ /**
+ * @param string The ID of the active accordion view.
+ */
+ public function setActiveViewID($value)
+ {
+ $this->setViewState('ActiveViewID',$value,'');
+ }
+
+ /**
+ * Returns the currently active view.
+ * This method will examin the ActiveViewID, ActiveViewIndex and Views collection to
+ * determine which view is currently active. It will update ActiveViewID and ActiveViewIndex accordingly.
+ * @return TAccordionView the currently active view, null if no active view
+ * @throws TInvalidDataValueException if the active view ID or index set previously is invalid
+ */
+ public function getActiveView()
+ {
+ $activeView=null;
+ $views=$this->getViews();
+ if(($id=$this->getActiveViewID())!=='')
+ {
+ if(($index=$views->findIndexByID($id))>=0)
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('tabpanel_activeviewid_invalid',$id);
+ }
+ else if(($index=$this->getActiveViewIndex())>=0)
+ {
+ if($index<$views->getCount())
+ $activeView=$views->itemAt($index);
+ else
+ throw new TInvalidDataValueException('tabpanel_activeviewindex_invalid',$index);
+ }
+ else
+ {
+ foreach($views as $index=>$view)
+ {
+ if($view->getActive())
+ {
+ $activeView=$view;
+ break;
+ }
+ }
+ }
+ if($activeView!==null)
+ $this->activateView($activeView);
+ return $activeView;
+ }
+
+ /**
+ * @param TAccordionView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($view)
+ {
+ if($this->getViews()->indexOf($view)>=0)
+ $this->activateView($view);
+ else
+ throw new TInvalidOperationException('tabpanel_view_inexistent');
+ }
+
+ /**
+ * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to ''.
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl','default');
+ }
+
+ /**
+ * @param string URL for the CSS file including all relevant CSS class definitions.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string CSS class for the whole accordion control div.
+ */
+ public function getCssClass()
+ {
+ $cssClass=parent::getCssClass();
+ return $cssClass===''?'accordion':$cssClass;
+ }
+
+ /**
+ * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
+ */
+ public function getViewCssClass()
+ {
+ return $this->getViewStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for the currently displayed view div.
+ */
+ public function setViewCssClass($value)
+ {
+ $this->getViewStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return string CSS class for the currently displayed view div. Defaults to 'accordion-view'.
+ */
+ public function getAnimationDuration()
+ {
+ return $this->getViewState('AnimationDuration','1');
+ }
+
+ /**
+ * @param string CSS class for the currently displayed view div.
+ */
+ public function setAnimationDuration($value)
+ {
+ $this->setViewState('AnimationDuration',$value);
+ }
+
+ /**
+ * @return TStyle the style for all the view div
+ */
+ public function getViewStyle()
+ {
+ if(($style=$this->getViewState('ViewStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-view');
+ $this->setViewState('ViewStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string CSS class for view headers. Defaults to 'accordion-header'.
+ */
+ public function getHeaderCssClass()
+ {
+ return $this->getHeaderStyle()->getCssClass();
+ }
+
+ /**
+ * @param string CSS class for view headers.
+ */
+ public function setHeaderCssClass($value)
+ {
+ $this->getHeaderStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for all the inactive header div
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-header');
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string Extra CSS class for the active header. Defaults to 'accordion-header-active'.
+ */
+ public function getActiveHeaderCssClass()
+ {
+ return $this->getActiveHeaderStyle()->getCssClass();
+ }
+
+ /**
+ * @param string Extra CSS class for the active header. Will be added to the normal header specified by HeaderCssClass.
+ */
+ public function setActiveHeaderCssClass($value)
+ {
+ $this->getActiveHeaderStyle()->setCssClass($value);
+ }
+
+ /**
+ * @return TStyle the style for the active header div
+ */
+ public function getActiveHeaderStyle()
+ {
+ if(($style=$this->getViewState('ActiveHeaderStyle',null))===null)
+ {
+ $style=new TStyle;
+ $style->setCssClass('accordion-header-active');
+ $this->setViewState('ActiveHeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return integer Maximum height for the accordion views. If non specified, the accordion will auto-sized to the largest of all views, so it can encompass all of them without scrolling
+ */
+ public function getViewHeight()
+ {
+ return TPropertyValue::ensureInteger($this->getViewState('ViewHeight'));
+ }
+
+ /**
+ * @param integer Maximum height for the accordion views. If any of the accordion's views' content is larger, those views will be made scrollable when activated
+ */
+ public function setViewHeight($value)
+ {
+ $this->setViewState('ViewHeight', TPropertyValue::ensureInteger($value));
+ }
+
+ /**
+ * Activates the specified view.
+ * If there is any other view currently active, it will be deactivated.
+ * @param TAccordionView the view to be activated. If null, all views will be deactivated.
+ */
+ protected function activateView($view)
+ {
+ $this->setActiveViewIndex(-1);
+ $this->setActiveViewID('');
+ foreach($this->getViews() as $index=>$v)
+ {
+ if($view===$v)
+ {
+ $this->setActiveViewIndex($index);
+ $this->setActiveViewID($view->getID(false));
+ $view->setActive(true);
+ }
+ else
+ $v->setActive(false);
+ }
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(($index=$values[$this->getClientID().'_1'])!==null)
+ {
+ $index=(int)$index;
+ $currentIndex=$this->getActiveViewIndex();
+ if($currentIndex!==$index)
+ {
+ $this->setActiveViewID(''); // clear up view ID
+ $this->setActiveViewIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getActiveViewIndex ActiveViewIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ // do nothing
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->setCssClass($this->getCssClass());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getActiveView(); // determine the active view
+ $this->registerStyleSheet();
+ }
+
+ /**
+ * Registers the CSS relevant to the TAccordion.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ $url = $this->getCssUrl();
+
+ if($url === '') {
+ return;
+ }
+
+ if($url === 'default') {
+ $url = $this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'accordion.css');
+ }
+
+ if($url !== '') {
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url, $url);
+ }
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $id=$this->getClientID();
+ $options=TJavaScript::encode($this->getClientOptions());
+ $className=$this->getClientClassName();
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ $cs->registerPradoScript('accordion');
+ $code="new $className($options);";
+ $cs->registerEndScript("prado:$id", $code);
+ // ensure an item is always active and visible
+ $index = $this->getActiveViewIndex();
+ if(!$this->getViews()->itemAt($index)->Visible)
+ $index=0;
+ $cs->registerHiddenField($id.'_1', $index);
+ $page->registerRequiresPostData($this);
+ $page->registerRequiresPostData($id."_1");
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TAccordion';
+ }
+
+ /**
+ * @return array the options for JavaScript
+ */
+ protected function getClientOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ActiveHeaderCssClass'] = $this->getActiveHeaderCssClass();
+ $options['HeaderCssClass'] = $this->getHeaderCssClass();
+ $options['Duration'] = $this->getAnimationDuration();
+
+ if (($viewheight = $this->getViewHeight())>0)
+ $options['maxHeight'] = $viewheight;
+ $views = array();
+ foreach($this->getViews() as $view)
+ $views[$view->getClientID()] = $view->getVisible() ? '1': '0';
+ $options['Views'] = $views;
+
+ return $options;
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TAccordionViewCollection control collection
+ */
+ protected function createControlCollection()
+ {
+ return new TAccordionViewCollection($this);
+ }
+
+ /**
+ * @return TAccordionViewCollection list of {@link TAccordionView} controls
+ */
+ public function getViews()
+ {
+ return $this->getControls();
+ }
+
+ public function render($writer)
+ {
+ $this->registerClientScript();
+ parent::render($writer);
+ }
+
+ /**
+ * Renders body contents of the accordion control.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ $views=$this->getViews();
+ if($views->getCount()>0)
+ {
+ $writer->writeLine();
+ foreach($views as $view)
+ {
+ $view->renderHeader($writer);
+ $view->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+
+}
+
+/**
+ * Class TAccordionView.
+ *
+ * TAccordionView represents a single view in a {@link TAccordion}.
+ *
+ * TAccordionView is represented inside the {@link TAccordion} with an header label whose text is defined by
+ * the {@link setCaption Caption} property; optionally the label can be an hyperlink: use the
+ * {@link setNavigateUrl NavigateUrl} property to define the destination url.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TAccordionView extends TWebControl
+{
+ private $_active=false;
+
+ /**
+ * @return the tag name for the view element
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if(!$this->getActive() && $this->getPage()->getClientSupportsJavaScript())
+ $this->getStyle()->setStyleField('display','none');
+
+ $this->getStyle()->mergeWith($this->getParent()->getViewStyle());
+
+ parent::addAttributesToRender($writer);
+
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * @return string the caption displayed on this header. Defaults to ''.
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string the caption displayed on this header
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL of the target page. Defaults to ''.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL of the target page.
+ * If not empty, clicking on this header will redirect the browser to the specified URL.
+ * @param string the URL of the target page.
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the text content displayed on this view. Defaults to ''.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content to be displayed on this view.
+ * If this is not empty, the child content of the view will be ignored.
+ * @param string the text content displayed on this view
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return boolean whether this accordion view is active. Defaults to false.
+ */
+ public function getActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * @param boolean whether this accordion view is active.
+ */
+ public function setActive($value)
+ {
+ $this->_active=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Renders body contents of the accordion view.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ }
+
+ /**
+ * Renders the header associated with the accordion view.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function renderHeader($writer)
+ {
+ if($this->getVisible(false) && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $writer->addAttribute('id',$this->getClientID().'_0');
+
+ $style=$this->getActive()?$this->getParent()->getActiveHeaderStyle():$this->getParent()->getHeaderStyle();
+
+ $style->addAttributesToRender($writer);
+
+ $writer->renderBeginTag($this->getTagName());
+
+ $this->renderHeaderContent($writer);
+
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the content in the header.
+ * By default, a hyperlink is displayed.
+ * @param THtmlWriter the HTML writer
+ */
+ protected function renderHeaderContent($writer)
+ {
+ $url = $this->getNavigateUrl();
+ if(($caption=$this->getCaption())==='')
+ $caption='&nbsp;';
+
+ if ($url!='')
+ $writer->write("<a href=\"{$url}\">");
+ $writer->write("{$caption}");
+ if ($url!='')
+ $writer->write("</a>");
+ }
+}
+
+/**
+ * Class TAccordionViewCollection.
+ *
+ * TAccordionViewCollection is a collection of {@link TAccordionView} to be used inside a {@link TAccordion}.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @version $Id: TAccordion.php 2915 2011-05-15 16:26:11Z ctrlaltca@gmail.com $
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TAccordionViewCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing sanity check on the type of new item.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TAccordionView} object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TAccordionView)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tabviewcollection_tabview_required');
+ }
+
+ /**
+ * Finds the index of the accordion view whose ID is the same as the one being looked for.
+ * @param string the explicit ID of the accordion view to be looked for
+ * @return integer the index of the accordion view found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ foreach($this as $index=>$view)
+ {
+ if($view->getID(false)===$id)
+ return $index;
+ }
+ return -1;
+ }
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TBaseDataList.php b/framework/Web/UI/WebControls/TBaseDataList.php
index bc591174..01e7dbcf 100644
--- a/framework/Web/UI/WebControls/TBaseDataList.php
+++ b/framework/Web/UI/WebControls/TBaseDataList.php
@@ -1,190 +1,190 @@
-<?php
-/**
- * TBaseDataList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TBaseDataList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TDataBoundControl and TDataFieldAccessor classes
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TBaseDataList class
- *
- * TBaseDataList is the base class for data listing controls, including
- * {@link TDataList} and {@link TDataGrid}.
- *
- * The key field in the data source is specified by {@link setKeyField KeyField},
- * while {@link getKeyValues KeyValues} stores the key values of each record in
- * a data listing control. You may use the list item index to obtain the corresponding
- * database key value.
- *
- * TBaseDataList also implements a few properties used for presentation based
- * on tabular layout. The {@link setCaption Caption}, whose alignment is
- * specified via {@link setCaptionAlign CaptionAlign}, is rendered as the table caption.
- * The table cellpadding and cellspacing are specified by
- * {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
- * properties, respectively. The {@link setGridLines GridLines} specifies how
- * the table should display its borders, and the horizontal alignment of the table
- * content can be specified via {@link setHorizontalAlign HorizontalAlign}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TBaseDataList extends TDataBoundControl
-{
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by the data list control.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return integer the cellspacing for the table layout. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * @param integer the cellspacing for the table layout.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table layout. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * @param integer the cellpadding for the table layout
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return THorizontalAlign::NotSet;
- }
-
- /**
- * @param THorizontalAlign the horizontal alignment of the table content.
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table layout. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getGridLines();
- else
- return TTableGridLines::None;
- }
-
- /**
- * Sets the grid line style of the table layout.
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->getStyle()->setGridLines($value);
- }
-
-
- /**
- * @return string the field of the data source that provides the keys of the list items.
- */
- public function getDataKeyField()
- {
- return $this->getViewState('DataKeyField','');
- }
-
- /**
- * @param string the field of the data source that provides the keys of the list items.
- */
- public function setDataKeyField($value)
- {
- $this->setViewState('DataKeyField',$value,'');
- }
-
- /**
- * @return TList the keys used in the data listing control.
- */
- public function getDataKeys()
- {
- if(($dataKeys=$this->getViewState('DataKeys',null))===null)
- {
- $dataKeys=new TList;
- $this->setViewState('DataKeys',$dataKeys,null);
- }
- return $dataKeys;
- }
-
- /**
- * Returns the value of the data at the specified field.
- * If data is an array, TMap or TList, the value will be returned at the index
- * of the specified field. If the data is a component with a property named
- * as the field name, the property value will be returned.
- * Otherwise, an exception will be raised.
- * @param mixed data item
- * @param mixed field name
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data is invalid
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-
- /**
- * Raises OnSelectedIndexChanged event.
- * This method is invoked when a different item is selected
- * in a data listing control between posts to the server.
- * @param mixed event parameter
- */
- public function onSelectedIndexChanged($param)
- {
- $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TDataBoundControl and TDataFieldAccessor classes
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TBaseDataList class
+ *
+ * TBaseDataList is the base class for data listing controls, including
+ * {@link TDataList} and {@link TDataGrid}.
+ *
+ * The key field in the data source is specified by {@link setKeyField KeyField},
+ * while {@link getKeyValues KeyValues} stores the key values of each record in
+ * a data listing control. You may use the list item index to obtain the corresponding
+ * database key value.
+ *
+ * TBaseDataList also implements a few properties used for presentation based
+ * on tabular layout. The {@link setCaption Caption}, whose alignment is
+ * specified via {@link setCaptionAlign CaptionAlign}, is rendered as the table caption.
+ * The table cellpadding and cellspacing are specified by
+ * {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
+ * properties, respectively. The {@link setGridLines GridLines} specifies how
+ * the table should display its borders, and the horizontal alignment of the table
+ * content can be specified via {@link setHorizontalAlign HorizontalAlign}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TBaseDataList extends TDataBoundControl
+{
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by the data list control.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return integer the cellspacing for the table layout. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellspacing for the table layout.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table layout. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellpadding for the table layout
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return THorizontalAlign::NotSet;
+ }
+
+ /**
+ * @param THorizontalAlign the horizontal alignment of the table content.
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table layout. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getGridLines();
+ else
+ return TTableGridLines::None;
+ }
+
+ /**
+ * Sets the grid line style of the table layout.
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->getStyle()->setGridLines($value);
+ }
+
+
+ /**
+ * @return string the field of the data source that provides the keys of the list items.
+ */
+ public function getDataKeyField()
+ {
+ return $this->getViewState('DataKeyField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the keys of the list items.
+ */
+ public function setDataKeyField($value)
+ {
+ $this->setViewState('DataKeyField',$value,'');
+ }
+
+ /**
+ * @return TList the keys used in the data listing control.
+ */
+ public function getDataKeys()
+ {
+ if(($dataKeys=$this->getViewState('DataKeys',null))===null)
+ {
+ $dataKeys=new TList;
+ $this->setViewState('DataKeys',$dataKeys,null);
+ }
+ return $dataKeys;
+ }
+
+ /**
+ * Returns the value of the data at the specified field.
+ * If data is an array, TMap or TList, the value will be returned at the index
+ * of the specified field. If the data is a component with a property named
+ * as the field name, the property value will be returned.
+ * Otherwise, an exception will be raised.
+ * @param mixed data item
+ * @param mixed field name
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data is invalid
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+
+ /**
+ * Raises OnSelectedIndexChanged event.
+ * This method is invoked when a different item is selected
+ * in a data listing control between posts to the server.
+ * @param mixed event parameter
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TBoundColumn.php b/framework/Web/UI/WebControls/TBoundColumn.php
index 43ef28c2..b7bbc5da 100644
--- a/framework/Web/UI/WebControls/TBoundColumn.php
+++ b/framework/Web/UI/WebControls/TBoundColumn.php
@@ -1,249 +1,249 @@
-<?php
-/**
- * TBoundColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TBoundColumn class
- *
- * TBoundColumn represents a column that is bound to a field in a data source.
- * The cells in the column will be displayed using the data indexed by
- * {@link setDataField DataField}. You can customize the display by
- * setting {@link setDataFormatString DataFormatString}.
- *
- * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode
- * with textboxes. Otherwise, a static text is displayed.
- *
- * When a datagrid row is in edit mode, the textbox control in the TBoundColumn
- * can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->BoundColumnID->TextBox
- * $datagridItem->BoundColumnID->Controls[0]
- * </code>
- * The second method is possible because the textbox control created within the
- * datagrid cell is the first child.
- *
- * Since v3.1.0, TBoundColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
- * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
- * the layout of the datagrid cells in browsing and editing mode.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBoundColumn extends TDataGridColumn
-{
- /**
- * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the data associated with the datagrid cell during databinding.
- * The data can be either the whole data row or a field of the row if
- * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
- * is not empty, the data will be formatted first before passing to the renderer.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the edit item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the data associated with the datagrid cell during databinding.
- * The data can be either the whole data row or a field of the row if
- * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
- * is not empty, the data will be formatted first before passing to the renderer.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataFormatString()
- {
- return $this->getViewState('DataFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataFormatString($value)
- {
- $this->setViewState('DataFormatString',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a textbox for item in edit mode and the column is not read-only.
- * Otherwise it displays a static text.
- * The caption of the button and the static text are retrieved
- * from the datasource.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- $item=$cell->getParent();
- switch($itemType)
- {
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- if(($classPath=$this->getItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- }
- else
- $control=$cell;
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- case TListItemType::EditItem:
- if(!$this->getReadOnly())
- {
- if(($classPath=$this->getEditItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- $cell->registerObject('EditControl',$control);
- }
- else
- {
- $control=Prado::createComponent('System.Web.UI.WebControls.TTextBox');
- $cell->getControls()->add($control);
- $cell->registerObject('TextBox',$control);
- }
- }
- else
- {
- if(($classPath=$this->getItemRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $cell->getControls()->add($control);
- }
- else
- $control=$cell;
- }
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- default:
- parent::initializeCell($cell,$columnIndex,$itemType);
- break;
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- $formatString=$this->getDataFormatString();
- if(($field=$this->getDataField())!=='')
- $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
- else
- $value=$this->formatDataValue($formatString,$data);
- $sender->setData($value);
- }
-}
-
+<?php
+/**
+ * TBoundColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TBoundColumn class
+ *
+ * TBoundColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setReadOnly ReadOnly} is false, TBoundColumn will display cells in edit mode
+ * with textboxes. Otherwise, a static text is displayed.
+ *
+ * When a datagrid row is in edit mode, the textbox control in the TBoundColumn
+ * can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->BoundColumnID->TextBox
+ * $datagridItem->BoundColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the textbox control created within the
+ * datagrid cell is the first child.
+ *
+ * Since v3.1.0, TBoundColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
+ * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
+ * the layout of the datagrid cells in browsing and editing mode.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBoundColumn extends TDataGridColumn
+{
+ /**
+ * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the data associated with the datagrid cell during databinding.
+ * The data can be either the whole data row or a field of the row if
+ * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
+ * is not empty, the data will be formatted first before passing to the renderer.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the edit item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the data associated with the datagrid cell during databinding.
+ * The data can be either the whole data row or a field of the row if
+ * {@link getDataField DataField} is not empty. If {@link getDataFormatString DataFormatString}
+ * is not empty, the data will be formatted first before passing to the renderer.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataFormatString()
+ {
+ return $this->getViewState('DataFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataFormatString($value)
+ {
+ $this->setViewState('DataFormatString',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a textbox for item in edit mode and the column is not read-only.
+ * Otherwise it displays a static text.
+ * The caption of the button and the static text are retrieved
+ * from the datasource.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ $item=$cell->getParent();
+ switch($itemType)
+ {
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ if(($classPath=$this->getItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ }
+ else
+ $control=$cell;
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ case TListItemType::EditItem:
+ if(!$this->getReadOnly())
+ {
+ if(($classPath=$this->getEditItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ $cell->registerObject('EditControl',$control);
+ }
+ else
+ {
+ $control=Prado::createComponent('System.Web.UI.WebControls.TTextBox');
+ $cell->getControls()->add($control);
+ $cell->registerObject('TextBox',$control);
+ }
+ }
+ else
+ {
+ if(($classPath=$this->getItemRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $cell->getControls()->add($control);
+ }
+ else
+ $control=$cell;
+ }
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ default:
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ break;
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ $formatString=$this->getDataFormatString();
+ if(($field=$this->getDataField())!=='')
+ $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
+ else
+ $value=$this->formatDataValue($formatString,$data);
+ $sender->setData($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TBulletedList.php b/framework/Web/UI/WebControls/TBulletedList.php
index 1b32059f..51982c3e 100644
--- a/framework/Web/UI/WebControls/TBulletedList.php
+++ b/framework/Web/UI/WebControls/TBulletedList.php
@@ -1,492 +1,492 @@
-<?php
-/**
- * TBulletedList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TBulletedList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TBulletedList class
- *
- * TBulletedList displays items in a bullet format.
- * The bullet style is specified by {@link setBulletStyle BulletStyle}. When
- * the style is 'CustomImage', the {@link setBackImageUrl BulletImageUrl}
- * specifies the image used as bullets.
- *
- * TBulletedList displays the item texts in three different modes, specified
- * via {@link setDisplayMode DisplayMode}. When the mode is Text, the item texts
- * are displayed as static texts; When the mode is 'HyperLink', each item
- * is displayed as a hyperlink whose URL is given by the item value, and the
- * {@link setTarget Target} property can be used to specify the target browser window;
- * When the mode is 'LinkButton', each item is displayed as a link button which
- * posts back to the page if a user clicks on that and the event {@link onClick OnClick}
- * will be raised under such a circumstance.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBulletedList extends TListControl implements IPostBackEventHandler
-{
- /**
- * @var boolean cached property value of Enabled
- */
- private $_isEnabled;
- /**
- * @var TPostBackOptions postback options
- */
- private $_postBackOptions;
-
- private $_currentRenderItemIndex;
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(new TBulletedListEventParameter((int)$param));
- }
-
- /**
- * @return string tag name of the bulleted list
- */
- protected function getTagName()
- {
- switch($this->getBulletStyle())
- {
- case TBulletStyle::Numbered:
- case TBulletStyle::LowerAlpha:
- case TBulletStyle::UpperAlpha:
- case TBulletStyle::LowerRoman:
- case TBulletStyle::UpperRoman:
- return 'ol';
- }
- return 'ul';
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TBulletedList';
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional bulleted list specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $needStart=false;
- switch($this->getBulletStyle())
- {
- case TBulletStyle::None:
- $writer->addStyleAttribute('list-style-type','none');
- $needStart=true;
- break;
- case TBulletStyle::Numbered:
- $writer->addStyleAttribute('list-style-type','decimal');
- $needStart=true;
- break;
- case TBulletStyle::LowerAlpha:
- $writer->addStyleAttribute('list-style-type','lower-alpha');
- $needStart=true;
- break;
- case TBulletStyle::UpperAlpha:
- $writer->addStyleAttribute('list-style-type','upper-alpha');
- $needStart=true;
- break;
- case TBulletStyle::LowerRoman:
- $writer->addStyleAttribute('list-style-type','lower-roman');
- $needStart=true;
- break;
- case TBulletStyle::UpperRoman:
- $writer->addStyleAttribute('list-style-type','upper-roman');
- $needStart=true;
- break;
- case TBulletStyle::Disc:
- $writer->addStyleAttribute('list-style-type','disc');
- break;
- case TBulletStyle::Circle:
- $writer->addStyleAttribute('list-style-type','circle');
- break;
- case TBulletStyle::Square:
- $writer->addStyleAttribute('list-style-type','square');
- break;
- case TBulletStyle::CustomImage:
- $url=$this->getBulletImageUrl();
- $writer->addStyleAttribute('list-style-image',"url($url)");
- break;
- }
- if($needStart && ($start=$this->getFirstBulletNumber())!=1)
- $writer->addAttribute('start',"$start");
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
- */
- public function getBulletImageUrl()
- {
- return $this->getViewState('BulletImageUrl','');
- }
-
- /**
- * @param string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
- */
- public function setBulletImageUrl($value)
- {
- $this->setViewState('BulletImageUrl',$value,'');
- }
-
- /**
- * @return TBulletStyle style of bullets. Defaults to TBulletStyle::NotSet.
- */
- public function getBulletStyle()
- {
- return $this->getViewState('BulletStyle',TBulletStyle::NotSet);
- }
-
- /**
- * @param TBulletStyle style of bullets.
- */
- public function setBulletStyle($value)
- {
- $this->setViewState('BulletStyle',TPropertyValue::ensureEnum($value,'TBulletStyle'),TBulletStyle::NotSet);
- }
-
- /**
- * @return TBulletedListDisplayMode display mode of the list. Defaults to TBulletedListDisplayMode::Text.
- */
- public function getDisplayMode()
- {
- return $this->getViewState('DisplayMode',TBulletedListDisplayMode::Text);
- }
-
- /**
- * @return TBulletedListDisplayMode display mode of the list.
- */
- public function setDisplayMode($value)
- {
- $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TBulletedListDisplayMode'),TBulletedListDisplayMode::Text);
- }
-
- /**
- * @return integer starting index when {@link getBulletStyle BulletStyle} is one of
- * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
- * Defaults to 1.
- */
- public function getFirstBulletNumber()
- {
- return $this->getViewState('FirstBulletNumber',1);
- }
-
- /**
- * @param integer starting index when {@link getBulletStyle BulletStyle} is one of
- * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
- */
- public function setFirstBulletNumber($value)
- {
- $this->setViewState('FirstBulletNumber',TPropertyValue::ensureInteger($value),1);
- }
-
- /**
- * Raises 'OnClick' event.
- * This method is invoked when the {@link getDisplayMode DisplayMode} is 'LinkButton'
- * and end-users click on one of the buttons.
- * @param TBulletedListEventParameter event parameter.
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * @return string the target window or frame to display the Web page content
- * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
- * the hyperlinks is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the Web page content
- * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
- * the hyperlinks is clicked.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-
- /**
- * Renders the control.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function render($writer)
- {
- if($this->getHasItems())
- parent::render($writer);
- }
-
- /**
- * Renders the body contents.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function renderContents($writer)
- {
- $this->_isEnabled=$this->getEnabled(true);
- $this->_postBackOptions=$this->getPostBackOptions();
- $writer->writeLine();
- foreach($this->getItems() as $index=>$item)
- {
- if($item->getHasAttributes())
- $writer->addAttributes($item->getAttributes());
- $writer->renderBeginTag('li');
- $this->renderBulletText($writer,$item,$index);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
-
- /**
- * Renders each item
- * @param THtmlWriter writer for the rendering purpose
- * @param TListItem item to be rendered
- * @param integer index of the item being rendered
- */
- protected function renderBulletText($writer,$item,$index)
- {
- switch($this->getDisplayMode())
- {
- case TBulletedListDisplayMode::Text:
- $this->renderTextItem($writer, $item, $index);
- break;
- case TBulletedListDisplayMode::HyperLink:
- $this->renderHyperLinkItem($writer, $item, $index);
- break;
- case TBulletedListDisplayMode::LinkButton:
- $this->renderLinkButtonItem($writer, $item, $index);
- break;
- }
- }
-
- protected function renderTextItem($writer, $item, $index)
- {
- if($item->getEnabled())
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- else
- {
- $writer->addAttribute('disabled','disabled');
- $writer->renderBeginTag('span');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
- }
-
- protected function renderHyperLinkItem($writer, $item, $index)
- {
- if(!$this->_isEnabled || !$item->getEnabled())
- $writer->addAttribute('disabled','disabled');
- else
- {
- $writer->addAttribute('href',$item->getValue());
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- $writer->renderBeginTag('a');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
-
- protected function renderLinkButtonItem($writer, $item, $index)
- {
- if(!$this->_isEnabled || !$item->getEnabled())
- $writer->addAttribute('disabled','disabled');
- else
- {
- $this->_currentRenderItemIndex = $index;
- $writer->addAttribute('id', $this->getClientID().$index);
- $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index);
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- $writer->renderBeginTag('a');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- }
-
- /**
- * @return array postback options used for linkbuttons.
- */
- protected function getPostBackOptions()
- {
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- $options['EventParameter'] = $this->_currentRenderItemIndex;
- $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex;
- $options['StopEvent'] = true;
- return $options;
- }
-
- protected function canCauseValidation()
- {
- $group = $this->getValidationGroup();
- $hasValidators = $this->getPage()->getValidators($group)->getCount()>0;
- return $this->getCausesValidation() && $hasValidators;
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setAutoPostBack($value)
- {
- throw new TNotSupportedException('bulletedlist_autopostback_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndex($index)
- {
- throw new TNotSupportedException('bulletedlist_selectedindex_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndices($indices)
- {
- throw new TNotSupportedException('bulletedlist_selectedindices_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedValue($value)
- {
- throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedValues($values)
- {
- throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
- }
-}
-
-/**
- * TBulletedListEventParameter
- * Event parameter for {@link TBulletedList::onClick Click} event of the
- * bulleted list. The {@link getIndex Index} gives the zero-based index
- * of the item that is currently being clicked.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TBulletedListEventParameter extends TEventParameter
-{
- /**
- * @var integer index of the item clicked
- */
- private $_index;
-
- /**
- * Constructor.
- * @param integer index of the item clicked
- */
- public function __construct($index)
- {
- $this->_index=$index;
- }
-
- /**
- * @return integer zero-based index of the item (rendered as a link button) that is clicked
- */
- public function getIndex()
- {
- return $this->_index;
- }
-}
-
-/**
- * TBulletStyle class.
- * TBulletStyle defines the enumerable type for the possible bullet styles that may be used
- * for a {@link TBulletedList} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TBulletStyle extends TEnumerable
-{
- const NotSet='NotSet';
- const None='None';
- const Numbered='Numbered';
- const LowerAlpha='LowerAlpha';
- const UpperAlpha='UpperAlpha';
- const LowerRoman='LowerRoman';
- const UpperRoman='UpperRoman';
- const Disc='Disc';
- const Circle='Circle';
- const Square='Square';
- const CustomImage='CustomImage';
-}
-
-/**
- * TBulletedListDisplayMode class.
- * TBulletedListDisplayMode defines the enumerable type for the possible display mode
- * of a {@link TBulletedList} control.
- *
- * The following enumerable values are defined:
- * - Text: the bulleted list items are displayed as plain texts
- * - HyperLink: the bulleted list items are displayed as hyperlinks
- * - LinkButton: the bulleted list items are displayed as link buttons that can cause postbacks
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TBulletedListDisplayMode extends TEnumerable
-{
- const Text='Text';
- const HyperLink='HyperLink';
- const LinkButton='LinkButton';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TBulletedList class
+ *
+ * TBulletedList displays items in a bullet format.
+ * The bullet style is specified by {@link setBulletStyle BulletStyle}. When
+ * the style is 'CustomImage', the {@link setBackImageUrl BulletImageUrl}
+ * specifies the image used as bullets.
+ *
+ * TBulletedList displays the item texts in three different modes, specified
+ * via {@link setDisplayMode DisplayMode}. When the mode is Text, the item texts
+ * are displayed as static texts; When the mode is 'HyperLink', each item
+ * is displayed as a hyperlink whose URL is given by the item value, and the
+ * {@link setTarget Target} property can be used to specify the target browser window;
+ * When the mode is 'LinkButton', each item is displayed as a link button which
+ * posts back to the page if a user clicks on that and the event {@link onClick OnClick}
+ * will be raised under such a circumstance.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBulletedList extends TListControl implements IPostBackEventHandler
+{
+ /**
+ * @var boolean cached property value of Enabled
+ */
+ private $_isEnabled;
+ /**
+ * @var TPostBackOptions postback options
+ */
+ private $_postBackOptions;
+
+ private $_currentRenderItemIndex;
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(new TBulletedListEventParameter((int)$param));
+ }
+
+ /**
+ * @return string tag name of the bulleted list
+ */
+ protected function getTagName()
+ {
+ switch($this->getBulletStyle())
+ {
+ case TBulletStyle::Numbered:
+ case TBulletStyle::LowerAlpha:
+ case TBulletStyle::UpperAlpha:
+ case TBulletStyle::LowerRoman:
+ case TBulletStyle::UpperRoman:
+ return 'ol';
+ }
+ return 'ul';
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TBulletedList';
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional bulleted list specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $needStart=false;
+ switch($this->getBulletStyle())
+ {
+ case TBulletStyle::None:
+ $writer->addStyleAttribute('list-style-type','none');
+ $needStart=true;
+ break;
+ case TBulletStyle::Numbered:
+ $writer->addStyleAttribute('list-style-type','decimal');
+ $needStart=true;
+ break;
+ case TBulletStyle::LowerAlpha:
+ $writer->addStyleAttribute('list-style-type','lower-alpha');
+ $needStart=true;
+ break;
+ case TBulletStyle::UpperAlpha:
+ $writer->addStyleAttribute('list-style-type','upper-alpha');
+ $needStart=true;
+ break;
+ case TBulletStyle::LowerRoman:
+ $writer->addStyleAttribute('list-style-type','lower-roman');
+ $needStart=true;
+ break;
+ case TBulletStyle::UpperRoman:
+ $writer->addStyleAttribute('list-style-type','upper-roman');
+ $needStart=true;
+ break;
+ case TBulletStyle::Disc:
+ $writer->addStyleAttribute('list-style-type','disc');
+ break;
+ case TBulletStyle::Circle:
+ $writer->addStyleAttribute('list-style-type','circle');
+ break;
+ case TBulletStyle::Square:
+ $writer->addStyleAttribute('list-style-type','square');
+ break;
+ case TBulletStyle::CustomImage:
+ $url=$this->getBulletImageUrl();
+ $writer->addStyleAttribute('list-style-image',"url($url)");
+ break;
+ }
+ if($needStart && ($start=$this->getFirstBulletNumber())!=1)
+ $writer->addAttribute('start',"$start");
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
+ */
+ public function getBulletImageUrl()
+ {
+ return $this->getViewState('BulletImageUrl','');
+ }
+
+ /**
+ * @param string image URL used for bullets when {@link getBulletStyle BulletStyle} is 'CustomImage'.
+ */
+ public function setBulletImageUrl($value)
+ {
+ $this->setViewState('BulletImageUrl',$value,'');
+ }
+
+ /**
+ * @return TBulletStyle style of bullets. Defaults to TBulletStyle::NotSet.
+ */
+ public function getBulletStyle()
+ {
+ return $this->getViewState('BulletStyle',TBulletStyle::NotSet);
+ }
+
+ /**
+ * @param TBulletStyle style of bullets.
+ */
+ public function setBulletStyle($value)
+ {
+ $this->setViewState('BulletStyle',TPropertyValue::ensureEnum($value,'TBulletStyle'),TBulletStyle::NotSet);
+ }
+
+ /**
+ * @return TBulletedListDisplayMode display mode of the list. Defaults to TBulletedListDisplayMode::Text.
+ */
+ public function getDisplayMode()
+ {
+ return $this->getViewState('DisplayMode',TBulletedListDisplayMode::Text);
+ }
+
+ /**
+ * @return TBulletedListDisplayMode display mode of the list.
+ */
+ public function setDisplayMode($value)
+ {
+ $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TBulletedListDisplayMode'),TBulletedListDisplayMode::Text);
+ }
+
+ /**
+ * @return integer starting index when {@link getBulletStyle BulletStyle} is one of
+ * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
+ * Defaults to 1.
+ */
+ public function getFirstBulletNumber()
+ {
+ return $this->getViewState('FirstBulletNumber',1);
+ }
+
+ /**
+ * @param integer starting index when {@link getBulletStyle BulletStyle} is one of
+ * the following: 'Numbered', 'LowerAlpha', 'UpperAlpha', 'LowerRoman', 'UpperRoman'.
+ */
+ public function setFirstBulletNumber($value)
+ {
+ $this->setViewState('FirstBulletNumber',TPropertyValue::ensureInteger($value),1);
+ }
+
+ /**
+ * Raises 'OnClick' event.
+ * This method is invoked when the {@link getDisplayMode DisplayMode} is 'LinkButton'
+ * and end-users click on one of the buttons.
+ * @param TBulletedListEventParameter event parameter.
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content
+ * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
+ * the hyperlinks is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the Web page content
+ * linked to when {@link getDisplayMode DisplayMode} is 'HyperLink' and one of
+ * the hyperlinks is clicked.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+
+ /**
+ * Renders the control.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getHasItems())
+ parent::render($writer);
+ }
+
+ /**
+ * Renders the body contents.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ $this->_isEnabled=$this->getEnabled(true);
+ $this->_postBackOptions=$this->getPostBackOptions();
+ $writer->writeLine();
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($item->getHasAttributes())
+ $writer->addAttributes($item->getAttributes());
+ $writer->renderBeginTag('li');
+ $this->renderBulletText($writer,$item,$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+
+ /**
+ * Renders each item
+ * @param THtmlWriter writer for the rendering purpose
+ * @param TListItem item to be rendered
+ * @param integer index of the item being rendered
+ */
+ protected function renderBulletText($writer,$item,$index)
+ {
+ switch($this->getDisplayMode())
+ {
+ case TBulletedListDisplayMode::Text:
+ $this->renderTextItem($writer, $item, $index);
+ break;
+ case TBulletedListDisplayMode::HyperLink:
+ $this->renderHyperLinkItem($writer, $item, $index);
+ break;
+ case TBulletedListDisplayMode::LinkButton:
+ $this->renderLinkButtonItem($writer, $item, $index);
+ break;
+ }
+ }
+
+ protected function renderTextItem($writer, $item, $index)
+ {
+ if($item->getEnabled())
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ else
+ {
+ $writer->addAttribute('disabled','disabled');
+ $writer->renderBeginTag('span');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+ }
+
+ protected function renderHyperLinkItem($writer, $item, $index)
+ {
+ if(!$this->_isEnabled || !$item->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ else
+ {
+ $writer->addAttribute('href',$item->getValue());
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ $writer->renderBeginTag('a');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+
+ protected function renderLinkButtonItem($writer, $item, $index)
+ {
+ if(!$this->_isEnabled || !$item->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ else
+ {
+ $this->_currentRenderItemIndex = $index;
+ $writer->addAttribute('id', $this->getClientID().$index);
+ $writer->addAttribute('href', "javascript:;//".$this->getClientID().$index);
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ $writer->renderBeginTag('a');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return array postback options used for linkbuttons.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['EventParameter'] = $this->_currentRenderItemIndex;
+ $options['ID'] = $this->getClientID().$this->_currentRenderItemIndex;
+ $options['StopEvent'] = true;
+ return $options;
+ }
+
+ protected function canCauseValidation()
+ {
+ $group = $this->getValidationGroup();
+ $hasValidators = $this->getPage()->getValidators($group)->getCount()>0;
+ return $this->getCausesValidation() && $hasValidators;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setAutoPostBack($value)
+ {
+ throw new TNotSupportedException('bulletedlist_autopostback_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndex($index)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedindex_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedindices_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedValue($value)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedValues($values)
+ {
+ throw new TNotSupportedException('bulletedlist_selectedvalue_unsupported');
+ }
+}
+
+/**
+ * TBulletedListEventParameter
+ * Event parameter for {@link TBulletedList::onClick Click} event of the
+ * bulleted list. The {@link getIndex Index} gives the zero-based index
+ * of the item that is currently being clicked.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TBulletedListEventParameter extends TEventParameter
+{
+ /**
+ * @var integer index of the item clicked
+ */
+ private $_index;
+
+ /**
+ * Constructor.
+ * @param integer index of the item clicked
+ */
+ public function __construct($index)
+ {
+ $this->_index=$index;
+ }
+
+ /**
+ * @return integer zero-based index of the item (rendered as a link button) that is clicked
+ */
+ public function getIndex()
+ {
+ return $this->_index;
+ }
+}
+
+/**
+ * TBulletStyle class.
+ * TBulletStyle defines the enumerable type for the possible bullet styles that may be used
+ * for a {@link TBulletedList} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TBulletStyle extends TEnumerable
+{
+ const NotSet='NotSet';
+ const None='None';
+ const Numbered='Numbered';
+ const LowerAlpha='LowerAlpha';
+ const UpperAlpha='UpperAlpha';
+ const LowerRoman='LowerRoman';
+ const UpperRoman='UpperRoman';
+ const Disc='Disc';
+ const Circle='Circle';
+ const Square='Square';
+ const CustomImage='CustomImage';
+}
+
+/**
+ * TBulletedListDisplayMode class.
+ * TBulletedListDisplayMode defines the enumerable type for the possible display mode
+ * of a {@link TBulletedList} control.
+ *
+ * The following enumerable values are defined:
+ * - Text: the bulleted list items are displayed as plain texts
+ * - HyperLink: the bulleted list items are displayed as hyperlinks
+ * - LinkButton: the bulleted list items are displayed as link buttons that can cause postbacks
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TBulletedListDisplayMode extends TEnumerable
+{
+ const Text='Text';
+ const HyperLink='HyperLink';
+ const LinkButton='LinkButton';
+}
+
diff --git a/framework/Web/UI/WebControls/TButton.php b/framework/Web/UI/WebControls/TButton.php
index 71256a5b..caa0332c 100644
--- a/framework/Web/UI/WebControls/TButton.php
+++ b/framework/Web/UI/WebControls/TButton.php
@@ -1,368 +1,368 @@
-<?php
-/**
- * TButton class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TButton class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TButton class
- *
- * TButton creates a click button on the page. It is mainly used to submit data to a page.
- *
- * TButton raises two server-side events, {@link onClick OnClick} and {@link onCommand OnCommand},
- * when it is clicked on the client-side. The difference between these two events
- * is that the event {@link onCommand OnCommand} is bubbled up to the button's ancestor controls.
- * And within the event parameter for {@link onCommand OnCommand} contains the reference
- * to the {@link setCommandName CommandName} and {@link setCommandParameter CommandParameter}
- * property values that are set for the button object. This allows you to create multiple TButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter.
- *
- * Clicking on button can also trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * The validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TButton displays the {@link setText Text} property as the button caption.
- *
- * TButton can be one of three {@link setButtonType ButtonType}: Submit, Button and Reset.
- * By default, it is a Submit button and the form submission uses the browser's
- * default submission capability. If it is Button or Reset, postback may occur
- * if one of the following conditions is met:
- * - an event handler is attached to {@link onClick OnClick} event;
- * - an event handler is attached to {@link onCommand OnCommand} event;
- * - the button is in a non-empty validation group.
- * In addition, clicking on a Reset button will clear up all input fields
- * if the button does not cause a postback.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
-{
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- $writer->addAttribute('type',strtolower($this->getButtonType()));
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- $writer->addAttribute('value',$this->getText());
- if($this->getEnabled(true))
- {
- if($this->getEnableClientScript() && $this->needPostBackScript())
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TButton';
- }
-
- /**
- * @return boolean whether to perform validation if the button is clicked
- */
- protected function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * @return boolean whether the button needs javascript to do postback
- */
- protected function needPostBackScript()
- {
- return $this->canCauseValidation() || ($this->getButtonType()!==TButtonType::Submit &&
- ($this->hasEventHandler('OnClick') || $this->hasEventHandler('OnCommand')))
- || $this->getIsDefaultButton();
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID']=$this->getClientID();
- $options['CausesValidation']=$this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- $options['ValidationGroup']=$this->getValidationGroup();
-
- return $options;
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * This overrides the parent implementation with nothing to be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(null);
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * @return string caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string caption of the button
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string caption of the button.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string caption of the button
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return TButtonType the type of the button. Defaults to TButtonType::Submit.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonType::Submit);
- }
-
- /**
- * @param TButtonType the type of the button.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonType'),TButtonType::Submit);
- }
-}
-
-/**
- * TButtonType class.
- * TButtonType defines the enumerable type for the possible types that a {@link TButton} can take.
- *
- * The following enumerable values are defined:
- * - Submit: a normal submit button
- * - Reset: a reset button
- * - Button: a client button (normally does not perform form submission)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TButtonType extends TEnumerable
-{
- const Submit='Submit';
- const Reset='Reset';
- const Button='Button';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TButton class
+ *
+ * TButton creates a click button on the page. It is mainly used to submit data to a page.
+ *
+ * TButton raises two server-side events, {@link onClick OnClick} and {@link onCommand OnCommand},
+ * when it is clicked on the client-side. The difference between these two events
+ * is that the event {@link onCommand OnCommand} is bubbled up to the button's ancestor controls.
+ * And within the event parameter for {@link onCommand OnCommand} contains the reference
+ * to the {@link setCommandName CommandName} and {@link setCommandParameter CommandParameter}
+ * property values that are set for the button object. This allows you to create multiple TButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter.
+ *
+ * Clicking on button can also trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * The validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TButton displays the {@link setText Text} property as the button caption.
+ *
+ * TButton can be one of three {@link setButtonType ButtonType}: Submit, Button and Reset.
+ * By default, it is a Submit button and the form submission uses the browser's
+ * default submission capability. If it is Button or Reset, postback may occur
+ * if one of the following conditions is met:
+ * - an event handler is attached to {@link onClick OnClick} event;
+ * - an event handler is attached to {@link onCommand OnCommand} event;
+ * - the button is in a non-empty validation group.
+ * In addition, clicking on a Reset button will clear up all input fields
+ * if the button does not cause a postback.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
+{
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ $writer->addAttribute('type',strtolower($this->getButtonType()));
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ $writer->addAttribute('value',$this->getText());
+ if($this->getEnabled(true))
+ {
+ if($this->getEnableClientScript() && $this->needPostBackScript())
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TButton';
+ }
+
+ /**
+ * @return boolean whether to perform validation if the button is clicked
+ */
+ protected function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * @return boolean whether the button needs javascript to do postback
+ */
+ protected function needPostBackScript()
+ {
+ return $this->canCauseValidation() || ($this->getButtonType()!==TButtonType::Submit &&
+ ($this->hasEventHandler('OnClick') || $this->hasEventHandler('OnCommand')))
+ || $this->getIsDefaultButton();
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID']=$this->getClientID();
+ $options['CausesValidation']=$this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['ValidationGroup']=$this->getValidationGroup();
+
+ return $options;
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * This overrides the parent implementation with nothing to be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(null);
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * @return string caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string caption of the button.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string caption of the button
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return TButtonType the type of the button. Defaults to TButtonType::Submit.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonType::Submit);
+ }
+
+ /**
+ * @param TButtonType the type of the button.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonType'),TButtonType::Submit);
+ }
+}
+
+/**
+ * TButtonType class.
+ * TButtonType defines the enumerable type for the possible types that a {@link TButton} can take.
+ *
+ * The following enumerable values are defined:
+ * - Submit: a normal submit button
+ * - Reset: a reset button
+ * - Button: a client button (normally does not perform form submission)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TButtonType extends TEnumerable
+{
+ const Submit='Submit';
+ const Reset='Reset';
+ const Button='Button';
+}
+
diff --git a/framework/Web/UI/WebControls/TButtonColumn.php b/framework/Web/UI/WebControls/TButtonColumn.php
index 9d754004..f0f387e7 100644
--- a/framework/Web/UI/WebControls/TButtonColumn.php
+++ b/framework/Web/UI/WebControls/TButtonColumn.php
@@ -1,278 +1,278 @@
-<?php
-/**
- * TButtonColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TButtonColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-Prado::using('System.Web.UI.WebControls.TButton');
-Prado::using('System.Web.UI.WebControls.TLinkButton');
-Prado::using('System.Web.UI.WebControls.TImageButton');
-
-/**
- * TButtonColumn class
- *
- * TButtonColumn contains a user-defined command button, such as Add or Remove,
- * that corresponds with each row in the column.
- *
- * The caption of the buttons in the column is determined by {@link setText Text}
- * and {@link setDataTextField DataTextField} properties. If both are present,
- * the latter takes precedence. The {@link setDataTextField DataTextField} property
- * refers to the name of the field in datasource whose value will be used as the button caption.
- * If {@link setDataTextFormatString DataTextFormatString} is not empty,
- * the value will be formatted before rendering.
- *
- * The buttons in the column can be set to display as hyperlinks or push buttons
- * by setting the {@link setButtonType ButtonType} property.
- * The {@link setCommandName CommandName} will assign its value to
- * all button's <b>CommandName</b> property. The datagrid will capture
- * the command event where you can write event handlers based on different command names.
- * The buttons' <b>CausesValidation</b> and <b>ValidationGroup</b> property values
- * are determined by the column's corresponding properties.
- *
- * The buttons in the column can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->ButtonColumnID->Button
- * $datagridItem->ButtonColumnID->Controls[0]
- * </code>
- * The second method is possible because the button control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TButtonColumn extends TDataGridColumn
-{
- /**
- * @return string the text caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the button.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the button caption
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the button caption
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the button caption will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the button caption will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the URL of the image file for image buttons
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for image buttons
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the button image url
- */
- public function getDataImageUrlField()
- {
- return $this->getViewState('DataImageUrlField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the button image url
- */
- public function setDataImageUrlField($value)
- {
- $this->setViewState('DataImageUrlField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the button image url will be displayed.
- */
- public function getDataImageUrlFormatString()
- {
- return $this->getViewState('DataImageUrlFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the button image url will be displayed.
- */
- public function setDataImageUrlFormatString($value)
- {
- $this->setViewState('DataImageUrlFormatString',$value,'');
- }
-
- /**
- * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
- }
-
- /**
- * @param TButtonColumnType the type of command button
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
- }
-
- /**
- * @return string the command name associated with the <b>OnCommand</b> event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * Sets the command name associated with the <b>Command</b> event.
- * @param string the text caption to be set
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a command button within the cell.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $buttonType=$this->getButtonType();
- if($buttonType===TButtonColumnType::LinkButton)
- $button=new TLinkButton;
- else if($buttonType===TButtonColumnType::PushButton)
- $button=new TButton;
- else // image button
- {
- $button=new TImageButton;
- $button->setImageUrl($this->getImageUrl());
- }
- $button->setText($this->getText());
- $button->setCommandName($this->getCommandName());
- $button->setCausesValidation($this->getCausesValidation());
- $button->setValidationGroup($this->getValidationGroup());
- if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!==''))
- $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- $cell->getControls()->add($button);
- $cell->registerObject('Button',$button);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- if($sender instanceof IButtonControl)
- {
- if(($field=$this->getDataTextField())!=='')
- {
- $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
- $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
- $sender->setText($text);
- }
- if(($sender instanceof TImageButton) && ($field=$this->getDataImageUrlField())!=='')
- {
- $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
- $url=$this->formatDataValue($this->getDataImageUrlFormatString(),$value);
- $sender->setImageUrl($url);
- }
- }
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+Prado::using('System.Web.UI.WebControls.TButton');
+Prado::using('System.Web.UI.WebControls.TLinkButton');
+Prado::using('System.Web.UI.WebControls.TImageButton');
+
+/**
+ * TButtonColumn class
+ *
+ * TButtonColumn contains a user-defined command button, such as Add or Remove,
+ * that corresponds with each row in the column.
+ *
+ * The caption of the buttons in the column is determined by {@link setText Text}
+ * and {@link setDataTextField DataTextField} properties. If both are present,
+ * the latter takes precedence. The {@link setDataTextField DataTextField} property
+ * refers to the name of the field in datasource whose value will be used as the button caption.
+ * If {@link setDataTextFormatString DataTextFormatString} is not empty,
+ * the value will be formatted before rendering.
+ *
+ * The buttons in the column can be set to display as hyperlinks or push buttons
+ * by setting the {@link setButtonType ButtonType} property.
+ * The {@link setCommandName CommandName} will assign its value to
+ * all button's <b>CommandName</b> property. The datagrid will capture
+ * the command event where you can write event handlers based on different command names.
+ * The buttons' <b>CausesValidation</b> and <b>ValidationGroup</b> property values
+ * are determined by the column's corresponding properties.
+ *
+ * The buttons in the column can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->ButtonColumnID->Button
+ * $datagridItem->ButtonColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the button control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TButtonColumn extends TDataGridColumn
+{
+ /**
+ * @return string the text caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the button.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the button caption
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the button caption
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the button caption will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the button caption will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the URL of the image file for image buttons
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for image buttons
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the button image url
+ */
+ public function getDataImageUrlField()
+ {
+ return $this->getViewState('DataImageUrlField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the button image url
+ */
+ public function setDataImageUrlField($value)
+ {
+ $this->setViewState('DataImageUrlField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the button image url will be displayed.
+ */
+ public function getDataImageUrlFormatString()
+ {
+ return $this->getViewState('DataImageUrlFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the button image url will be displayed.
+ */
+ public function setDataImageUrlFormatString($value)
+ {
+ $this->setViewState('DataImageUrlFormatString',$value,'');
+ }
+
+ /**
+ * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @param TButtonColumnType the type of command button
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @return string the command name associated with the <b>OnCommand</b> event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * Sets the command name associated with the <b>Command</b> event.
+ * @param string the text caption to be set
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a command button within the cell.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $buttonType=$this->getButtonType();
+ if($buttonType===TButtonColumnType::LinkButton)
+ $button=new TLinkButton;
+ else if($buttonType===TButtonColumnType::PushButton)
+ $button=new TButton;
+ else // image button
+ {
+ $button=new TImageButton;
+ $button->setImageUrl($this->getImageUrl());
+ }
+ $button->setText($this->getText());
+ $button->setCommandName($this->getCommandName());
+ $button->setCausesValidation($this->getCausesValidation());
+ $button->setValidationGroup($this->getValidationGroup());
+ if($this->getDataTextField()!=='' || ($buttonType===TButtonColumnType::ImageButton && $this->getDataImageUrlField()!==''))
+ $button->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($button);
+ $cell->registerObject('Button',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ if($sender instanceof IButtonControl)
+ {
+ if(($field=$this->getDataTextField())!=='')
+ {
+ $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
+ $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
+ $sender->setText($text);
+ }
+ if(($sender instanceof TImageButton) && ($field=$this->getDataImageUrlField())!=='')
+ {
+ $value=$this->getDataFieldValue($sender->getNamingContainer()->getData(),$field);
+ $url=$this->formatDataValue($this->getDataImageUrlFormatString(),$value);
+ $sender->setImageUrl($url);
+ }
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCaptcha.php b/framework/Web/UI/WebControls/TCaptcha.php
index 7bcf5643..5ec870ce 100644
--- a/framework/Web/UI/WebControls/TCaptcha.php
+++ b/framework/Web/UI/WebControls/TCaptcha.php
@@ -1,495 +1,495 @@
-<?php
-/**
- * TCaptcha class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TCaptcha class.
- *
- * Notice: while this class is easy to use and implement, it does not provide full security.
- * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
- * A better alternative is provided by {@link TReCaptcha}.
- *
- * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used
- * to determine if the input is entered by a real user instead of some program.
- *
- * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie.
- *
- * The token (a string consisting of alphanumeric characters) displayed is automatically
- * generated and can be configured in several ways. To specify the length of characters
- * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}.
- * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive}
- * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
- * specifies what characters can appear in tokens.
- *
- * The validation of the token is related with two properties: {@link setTestLimit TestLimit}
- * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can
- * be tested with on the server side, and the latter says when a generated token will expire.
- *
- * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme}
- * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize}
- * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.)
- * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background
- * of the token will be variating even though the token is the same during postbacks.
- *
- * Upon postback, user input can be validated by calling {@link validate()}.
- * The {@link TCaptchaValidator} control can also be used to do validation, which provides
- * client-side validation besides the server-side validation. By default, the token will
- * remain the same during multiple postbacks. A new one can be generated by calling
- * {@link regenerateToken()} manually.
- *
- * The following template shows a typical use of TCaptcha control:
- * <code>
- * <com:TCaptcha ID="Captcha" />
- * <com:TTextBox ID="Input" />
- * <com:TCaptchaValidator CaptchaControl="Captcha"
- * ControlToValidate="Input"
- * ErrorMessage="You are challenged!" />
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TCaptcha extends TImage
-{
- const MIN_TOKEN_LENGTH=2;
- const MAX_TOKEN_LENGTH=40;
- private $_privateKey;
- private $_validated=false;
-
- /**
- * @return integer the theme of the token image. Defaults to 0.
- */
- public function getTokenImageTheme()
- {
- return $this->getViewState('TokenImageTheme',0);
- }
-
- /**
- * Sets the theme of the token image.
- * You may test each theme to find out the one you like the most.
- * Below is the explanation of the theme value:
- * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image.
- * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0).
- * Bit 1: whether we should add white noise to the image (1) or not (0).
- * Bit 2: whether we should add a grid to the image (1) or not (0).
- * Bit 3: whether we should add some scribbles to the image (1) or not (0).
- * Bit 4: whether the image background should be morphed (1) or not (0).
- * Bit 5: whether the token text should cast a shadow (1) or not (0).
- * @param integer the theme of the token image. It must be an integer between 0 and 63.
- */
- public function setTokenImageTheme($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value>=0 && $value<=63)
- $this->setViewState('TokenImageTheme',$value,0);
- else
- throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63);
- }
-
- /**
- * @return integer the font size used for displaying the token in an image. Defaults to 30.
- */
- public function getTokenFontSize()
- {
- return $this->getViewState('TokenFontSize',30);
- }
-
- /**
- * Sets the font size used for displaying the token in an image.
- * This property affects the generated token image size.
- * The image width is proportional to this font size.
- * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100.
- */
- public function setTokenFontSize($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value>=20 && $value<=100)
- $this->setViewState('TokenFontSize',$value,30);
- else
- throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100);
- }
-
- /**
- * @return integer the minimum length of the token. Defaults to 4.
- */
- public function getMinTokenLength()
- {
- return $this->getViewState('MinTokenLength',4);
- }
-
- /**
- * @param integer the minimum length of the token. It must be between 2 and 40.
- */
- public function setMinTokenLength($value)
- {
- $length=TPropertyValue::ensureInteger($value);
- if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MinTokenLength',$length,4);
- else
- throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
- }
-
- /**
- * @return integer the maximum length of the token. Defaults to 6.
- */
- public function getMaxTokenLength()
- {
- return $this->getViewState('MaxTokenLength',6);
- }
-
- /**
- * @param integer the maximum length of the token. It must be between 2 and 40.
- */
- public function setMaxTokenLength($value)
- {
- $length=TPropertyValue::ensureInteger($value);
- if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
- $this->setViewState('MaxTokenLength',$length,6);
- else
- throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
- }
-
- /**
- * @return boolean whether the token should be treated as case-sensitive. Defaults to true.
- */
- public function getCaseSensitive()
- {
- return $this->getViewState('CaseSensitive',true);
- }
-
- /**
- * @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token.
- */
- public function setCaseSensitive($value)
- {
- $this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'.
- */
- public function getTokenAlphabet()
- {
- return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT');
- }
-
- /**
- * @param string the characters that may appear in the token. At least 2 characters must be specified.
- */
- public function setTokenAlphabet($value)
- {
- if(strlen($value)<2)
- throw new TConfigurationException('captcha_tokenalphabet_invalid');
- $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT');
- }
-
- /**
- * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes).
- */
- public function getTokenExpiry()
- {
- return $this->getViewState('TokenExpiry',600);
- }
-
- /**
- * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire.
- */
- public function setTokenExpiry($value)
- {
- $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600);
- }
-
- /**
- * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false.
- */
- public function getChangingTokenBackground()
- {
- return $this->getViewState('ChangingTokenBackground',false);
- }
-
- /**
- * @param boolean whether the background of the token image should be variated during postbacks.
- */
- public function setChangingTokenBackground($value)
- {
- $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer how many times a generated token can be tested. Defaults to 5.
- */
- public function getTestLimit()
- {
- return $this->getViewState('TestLimit',5);
- }
-
- /**
- * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0.
- */
- public function setTestLimit($value)
- {
- $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5);
- }
-
- /**
- * @return boolean whether the currently generated token has expired.
- */
- public function getIsTokenExpired()
- {
- if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0)
- return $expiry+$start<time();
- else
- return false;
- }
-
- /**
- * @return string the public key used for generating the token. A random one will be generated and returned if this is not set.
- */
- public function getPublicKey()
- {
- if(($publicKey=$this->getViewState('PublicKey',''))==='')
- {
- $publicKey=$this->generateRandomKey();
- $this->setPublicKey($publicKey);
- }
- return $publicKey;
- }
-
- /**
- * @param string the public key used for generating the token. A random one will be generated if this is not set.
- */
- public function setPublicKey($value)
- {
- $this->setViewState('PublicKey',$value,'');
- }
-
- /**
- * @return string the token that will be displayed
- */
- public function getToken()
- {
- return $this->generateToken($this->getPublicKey(),$this->getPrivateKey(),$this->getTokenAlphabet(),$this->getTokenLength(),$this->getCaseSensitive());
- }
-
- /**
- * @return integer the length of the token to be generated.
- */
- protected function getTokenLength()
- {
- if(($tokenLength=$this->getViewState('TokenLength'))===null)
- {
- $minLength=$this->getMinTokenLength();
- $maxLength=$this->getMaxTokenLength();
- if($minLength>$maxLength)
- $tokenLength=rand($maxLength,$minLength);
- else if($minLength<$maxLength)
- $tokenLength=rand($minLength,$maxLength);
- else
- $tokenLength=$minLength;
- $this->setViewState('TokenLength',$tokenLength);
- }
- return $tokenLength;
- }
-
- /**
- * @return string the private key used for generating the token. This is randomly generated and kept in a file for persistency.
- */
- public function getPrivateKey()
- {
- if($this->_privateKey===null)
- {
- $fileName=$this->generatePrivateKeyFile();
- $content=file_get_contents($fileName);
- $matches=array();
- if(preg_match("/privateKey='(.*?)'/ms",$content,$matches)>0)
- $this->_privateKey=$matches[1];
- else
- throw new TConfigurationException('captcha_privatekey_unknown');
- }
- return $this->_privateKey;
- }
-
- /**
- * Validates a user input with the token.
- * @param string user input
- * @return boolean if the user input is not the same as the token.
- */
- public function validate($input)
- {
- $number=$this->getViewState('TestNumber',0);
- if(!$this->_validated)
- {
- $this->setViewState('TestNumber',++$number);
- $this->_validated=true;
- }
- if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit))
- {
- $this->regenerateToken();
- return false;
- }
- return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input)));
- }
-
- /**
- * Regenerates the token to be displayed.
- * By default, a token, once generated, will remain the same during the following page postbacks.
- * Calling this method will generate a new token.
- */
- public function regenerateToken()
- {
- $this->clearViewState('TokenLength');
- $this->setPublicKey('');
- $this->clearViewState('TokenGenerated');
- $this->clearViewState('RandomSeed');
- $this->clearViewState('TestNumber',0);
- }
-
- /**
- * Configures the image URL that shows the token.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if(!self::checkRequirements())
- throw new TConfigurationException('captcha_imagettftext_required');
- if(!$this->getViewState('TokenGenerated',0))
- {
- $manager=$this->getApplication()->getAssetManager();
- $manager->publishFilePath($this->getFontFile());
- $url=$manager->publishFilePath($this->getCaptchaScriptFile());
- $url.='?options='.urlencode($this->getTokenImageOptions());
- $this->setImageUrl($url);
-
- $this->setViewState('TokenGenerated',time());
- }
- }
-
- /**
- * @return string the options to be passed to the token image generator
- */
- protected function getTokenImageOptions()
- {
- $privateKey=$this->getPrivateKey(); // call this method to ensure private key is generated
- $token=$this->getToken();
- $options=array();
- $options['publicKey']=$this->getPublicKey();
- $options['tokenLength']=strlen($token);
- $options['caseSensitive']=$this->getCaseSensitive();
- $options['alphabet']=$this->getTokenAlphabet();
- $options['fontSize']=$this->getTokenFontSize();
- $options['theme']=$this->getTokenImageTheme();
- if(($randomSeed=$this->getViewState('RandomSeed',0))===0)
- {
- $randomSeed=(int)(microtime()*1000000);
- $this->setViewState('RandomSeed',$randomSeed);
- }
- $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed;
- $str=serialize($options);
- return base64_encode(md5($privateKey.$str).$str);
- }
-
- /**
- * @return string the file path of the PHP script generating the token image
- */
- protected function getCaptchaScriptFile()
- {
- return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'captcha.php';
- }
-
- protected function getFontFile()
- {
- return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'verase.ttf';
- }
-
- /**
- * Generates a file with a randomly generated private key.
- * @return string the path of the file keeping the private key
- */
- protected function generatePrivateKeyFile()
- {
- $captchaScript=$this->getCaptchaScriptFile();
- $path=dirname($this->getApplication()->getAssetManager()->getPublishedPath($captchaScript));
- $fileName=$path.DIRECTORY_SEPARATOR.'captcha_key.php';
- if(!is_file($fileName))
- {
- @mkdir($path);
- $key=$this->generateRandomKey();
- $content="<?php
-\$privateKey='$key';
-?>";
- file_put_contents($fileName,$content);
- }
- return $fileName;
- }
-
- /**
- * @return string a randomly generated key
- */
- protected function generateRandomKey()
- {
- return md5(rand().rand().rand().rand());
- }
-
- /**
- * Generates the token.
- * @param string public key
- * @param string private key
- * @param integer the length of the token
- * @param boolean whether the token is case sensitive
- * @return string the token generated.
- */
- protected function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
- {
- $token=substr($this->hash2string(md5($publicKey.$privateKey),$alphabet).$this->hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
- return $caseSensitive?$token:strtoupper($token);
- }
-
- /**
- * Converts a hash string into a string with characters consisting of alphanumeric characters.
- * @param string the hexadecimal representation of the hash string
- * @param string the alphabet used to represent the converted string. If empty, it means '234578adefhijmnrtwyABDEFGHIJLMNQRTWY', which excludes those confusing characters.
- * @return string the converted string
- */
- protected function hash2string($hex,$alphabet='')
- {
- if(strlen($alphabet)<2)
- $alphabet='234578adefhijmnrtABDEFGHJLMNQRT';
- $hexLength=strlen($hex);
- $base=strlen($alphabet);
- $result='';
- for($i=0;$i<$hexLength;$i+=6)
- {
- $number=hexdec(substr($hex,$i,6));
- while($number)
- {
- $result.=$alphabet[$number%$base];
- $number=floor($number/$base);
- }
- }
- return $result;
- }
-
- /**
- * Checks the requirements needed for generating CAPTCHA images.
- * TCaptach requires GD2 with TrueType font support and PNG image support.
- * @return boolean whether the requirements are satisfied.
- */
- public static function checkRequirements()
- {
- return extension_loaded('gd') && function_exists('imagettftext') && function_exists('imagepng');
- }
-}
-
+<?php
+/**
+ * TCaptcha class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TCaptcha class.
+ *
+ * Notice: while this class is easy to use and implement, it does not provide full security.
+ * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
+ * A better alternative is provided by {@link TReCaptcha}.
+ *
+ * TCaptcha displays a CAPTCHA (a token displayed as an image) that can be used
+ * to determine if the input is entered by a real user instead of some program.
+ *
+ * Unlike other CAPTCHA scripts, TCaptcha does not need session or cookie.
+ *
+ * The token (a string consisting of alphanumeric characters) displayed is automatically
+ * generated and can be configured in several ways. To specify the length of characters
+ * in the token, set {@link setMinTokenLength MinTokenLength} and {@link setMaxTokenLength MaxTokenLength}.
+ * To use case-insensitive comparison and generate upper-case-only token, set {@link setCaseSensitive CaseSensitive}
+ * to false. Advanced users can try to set {@link setTokenAlphabet TokenAlphabet}, which
+ * specifies what characters can appear in tokens.
+ *
+ * The validation of the token is related with two properties: {@link setTestLimit TestLimit}
+ * and {@link setTokenExpiry TokenExpiry}. The former specifies how many times a token can
+ * be tested with on the server side, and the latter says when a generated token will expire.
+ *
+ * To specify the appearance of the generated token image, set {@link setTokenImageTheme TokenImageTheme}
+ * to be an integer between 0 and 63. And to adjust the generated image size, set {@link setTokenFontSize TokenFontSize}
+ * (you may also set {@link TWebControl::setWidth Width}, but the scaled image may not look good.)
+ * By setting {@link setChangingTokenBackground ChangingTokenBackground} to true, the image background
+ * of the token will be variating even though the token is the same during postbacks.
+ *
+ * Upon postback, user input can be validated by calling {@link validate()}.
+ * The {@link TCaptchaValidator} control can also be used to do validation, which provides
+ * client-side validation besides the server-side validation. By default, the token will
+ * remain the same during multiple postbacks. A new one can be generated by calling
+ * {@link regenerateToken()} manually.
+ *
+ * The following template shows a typical use of TCaptcha control:
+ * <code>
+ * <com:TCaptcha ID="Captcha" />
+ * <com:TTextBox ID="Input" />
+ * <com:TCaptchaValidator CaptchaControl="Captcha"
+ * ControlToValidate="Input"
+ * ErrorMessage="You are challenged!" />
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TCaptcha extends TImage
+{
+ const MIN_TOKEN_LENGTH=2;
+ const MAX_TOKEN_LENGTH=40;
+ private $_privateKey;
+ private $_validated=false;
+
+ /**
+ * @return integer the theme of the token image. Defaults to 0.
+ */
+ public function getTokenImageTheme()
+ {
+ return $this->getViewState('TokenImageTheme',0);
+ }
+
+ /**
+ * Sets the theme of the token image.
+ * You may test each theme to find out the one you like the most.
+ * Below is the explanation of the theme value:
+ * It is treated as a 5-bit integer. Each bit toggles a specific feature of the image.
+ * Bit 0 (the least significant): whether the image is opaque (1) or transparent (0).
+ * Bit 1: whether we should add white noise to the image (1) or not (0).
+ * Bit 2: whether we should add a grid to the image (1) or not (0).
+ * Bit 3: whether we should add some scribbles to the image (1) or not (0).
+ * Bit 4: whether the image background should be morphed (1) or not (0).
+ * Bit 5: whether the token text should cast a shadow (1) or not (0).
+ * @param integer the theme of the token image. It must be an integer between 0 and 63.
+ */
+ public function setTokenImageTheme($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=0 && $value<=63)
+ $this->setViewState('TokenImageTheme',$value,0);
+ else
+ throw new TConfigurationException('captcha_tokenimagetheme_invalid',0,63);
+ }
+
+ /**
+ * @return integer the font size used for displaying the token in an image. Defaults to 30.
+ */
+ public function getTokenFontSize()
+ {
+ return $this->getViewState('TokenFontSize',30);
+ }
+
+ /**
+ * Sets the font size used for displaying the token in an image.
+ * This property affects the generated token image size.
+ * The image width is proportional to this font size.
+ * @param integer the font size used for displaying the token in an image. It must be an integer between 20 and 100.
+ */
+ public function setTokenFontSize($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value>=20 && $value<=100)
+ $this->setViewState('TokenFontSize',$value,30);
+ else
+ throw new TConfigurationException('captcha_tokenfontsize_invalid',20,100);
+ }
+
+ /**
+ * @return integer the minimum length of the token. Defaults to 4.
+ */
+ public function getMinTokenLength()
+ {
+ return $this->getViewState('MinTokenLength',4);
+ }
+
+ /**
+ * @param integer the minimum length of the token. It must be between 2 and 40.
+ */
+ public function setMinTokenLength($value)
+ {
+ $length=TPropertyValue::ensureInteger($value);
+ if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
+ $this->setViewState('MinTokenLength',$length,4);
+ else
+ throw new TConfigurationException('captcha_mintokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
+ }
+
+ /**
+ * @return integer the maximum length of the token. Defaults to 6.
+ */
+ public function getMaxTokenLength()
+ {
+ return $this->getViewState('MaxTokenLength',6);
+ }
+
+ /**
+ * @param integer the maximum length of the token. It must be between 2 and 40.
+ */
+ public function setMaxTokenLength($value)
+ {
+ $length=TPropertyValue::ensureInteger($value);
+ if($length>=self::MIN_TOKEN_LENGTH && $length<=self::MAX_TOKEN_LENGTH)
+ $this->setViewState('MaxTokenLength',$length,6);
+ else
+ throw new TConfigurationException('captcha_maxtokenlength_invalid',self::MIN_TOKEN_LENGTH,self::MAX_TOKEN_LENGTH);
+ }
+
+ /**
+ * @return boolean whether the token should be treated as case-sensitive. Defaults to true.
+ */
+ public function getCaseSensitive()
+ {
+ return $this->getViewState('CaseSensitive',true);
+ }
+
+ /**
+ * @param boolean whether the token should be treated as case-sensitive. If false, only upper-case letters will appear in the token.
+ */
+ public function setCaseSensitive($value)
+ {
+ $this->setViewState('CaseSensitive',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the characters that may appear in the token. Defaults to '234578adefhijmnrtABDEFGHJLMNRT'.
+ */
+ public function getTokenAlphabet()
+ {
+ return $this->getViewState('TokenAlphabet','234578adefhijmnrtABDEFGHJLMNRT');
+ }
+
+ /**
+ * @param string the characters that may appear in the token. At least 2 characters must be specified.
+ */
+ public function setTokenAlphabet($value)
+ {
+ if(strlen($value)<2)
+ throw new TConfigurationException('captcha_tokenalphabet_invalid');
+ $this->setViewState('TokenAlphabet',$value,'234578adefhijmnrtABDEFGHJLMNRT');
+ }
+
+ /**
+ * @return integer the number of seconds that a generated token will remain valid. Defaults to 600 seconds (10 minutes).
+ */
+ public function getTokenExpiry()
+ {
+ return $this->getViewState('TokenExpiry',600);
+ }
+
+ /**
+ * @param integer the number of seconds that a generated token will remain valid. A value smaller than 1 means the token will not expire.
+ */
+ public function setTokenExpiry($value)
+ {
+ $this->setViewState('TokenExpiry',TPropertyValue::ensureInteger($value),600);
+ }
+
+ /**
+ * @return boolean whether the background of the token image should be variated during postbacks. Defaults to false.
+ */
+ public function getChangingTokenBackground()
+ {
+ return $this->getViewState('ChangingTokenBackground',false);
+ }
+
+ /**
+ * @param boolean whether the background of the token image should be variated during postbacks.
+ */
+ public function setChangingTokenBackground($value)
+ {
+ $this->setViewState('ChangingTokenBackground',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer how many times a generated token can be tested. Defaults to 5.
+ */
+ public function getTestLimit()
+ {
+ return $this->getViewState('TestLimit',5);
+ }
+
+ /**
+ * @param integer how many times a generated token can be tested. For unlimited tests, set it to 0.
+ */
+ public function setTestLimit($value)
+ {
+ $this->setViewState('TestLimit',TPropertyValue::ensureInteger($value),5);
+ }
+
+ /**
+ * @return boolean whether the currently generated token has expired.
+ */
+ public function getIsTokenExpired()
+ {
+ if(($expiry=$this->getTokenExpiry())>0 && ($start=$this->getViewState('TokenGenerated',0))>0)
+ return $expiry+$start<time();
+ else
+ return false;
+ }
+
+ /**
+ * @return string the public key used for generating the token. A random one will be generated and returned if this is not set.
+ */
+ public function getPublicKey()
+ {
+ if(($publicKey=$this->getViewState('PublicKey',''))==='')
+ {
+ $publicKey=$this->generateRandomKey();
+ $this->setPublicKey($publicKey);
+ }
+ return $publicKey;
+ }
+
+ /**
+ * @param string the public key used for generating the token. A random one will be generated if this is not set.
+ */
+ public function setPublicKey($value)
+ {
+ $this->setViewState('PublicKey',$value,'');
+ }
+
+ /**
+ * @return string the token that will be displayed
+ */
+ public function getToken()
+ {
+ return $this->generateToken($this->getPublicKey(),$this->getPrivateKey(),$this->getTokenAlphabet(),$this->getTokenLength(),$this->getCaseSensitive());
+ }
+
+ /**
+ * @return integer the length of the token to be generated.
+ */
+ protected function getTokenLength()
+ {
+ if(($tokenLength=$this->getViewState('TokenLength'))===null)
+ {
+ $minLength=$this->getMinTokenLength();
+ $maxLength=$this->getMaxTokenLength();
+ if($minLength>$maxLength)
+ $tokenLength=rand($maxLength,$minLength);
+ else if($minLength<$maxLength)
+ $tokenLength=rand($minLength,$maxLength);
+ else
+ $tokenLength=$minLength;
+ $this->setViewState('TokenLength',$tokenLength);
+ }
+ return $tokenLength;
+ }
+
+ /**
+ * @return string the private key used for generating the token. This is randomly generated and kept in a file for persistency.
+ */
+ public function getPrivateKey()
+ {
+ if($this->_privateKey===null)
+ {
+ $fileName=$this->generatePrivateKeyFile();
+ $content=file_get_contents($fileName);
+ $matches=array();
+ if(preg_match("/privateKey='(.*?)'/ms",$content,$matches)>0)
+ $this->_privateKey=$matches[1];
+ else
+ throw new TConfigurationException('captcha_privatekey_unknown');
+ }
+ return $this->_privateKey;
+ }
+
+ /**
+ * Validates a user input with the token.
+ * @param string user input
+ * @return boolean if the user input is not the same as the token.
+ */
+ public function validate($input)
+ {
+ $number=$this->getViewState('TestNumber',0);
+ if(!$this->_validated)
+ {
+ $this->setViewState('TestNumber',++$number);
+ $this->_validated=true;
+ }
+ if($this->getIsTokenExpired() || (($limit=$this->getTestLimit())>0 && $number>$limit))
+ {
+ $this->regenerateToken();
+ return false;
+ }
+ return ($this->getToken()===($this->getCaseSensitive()?$input:strtoupper($input)));
+ }
+
+ /**
+ * Regenerates the token to be displayed.
+ * By default, a token, once generated, will remain the same during the following page postbacks.
+ * Calling this method will generate a new token.
+ */
+ public function regenerateToken()
+ {
+ $this->clearViewState('TokenLength');
+ $this->setPublicKey('');
+ $this->clearViewState('TokenGenerated');
+ $this->clearViewState('RandomSeed');
+ $this->clearViewState('TestNumber',0);
+ }
+
+ /**
+ * Configures the image URL that shows the token.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if(!self::checkRequirements())
+ throw new TConfigurationException('captcha_imagettftext_required');
+ if(!$this->getViewState('TokenGenerated',0))
+ {
+ $manager=$this->getApplication()->getAssetManager();
+ $manager->publishFilePath($this->getFontFile());
+ $url=$manager->publishFilePath($this->getCaptchaScriptFile());
+ $url.='?options='.urlencode($this->getTokenImageOptions());
+ $this->setImageUrl($url);
+
+ $this->setViewState('TokenGenerated',time());
+ }
+ }
+
+ /**
+ * @return string the options to be passed to the token image generator
+ */
+ protected function getTokenImageOptions()
+ {
+ $privateKey=$this->getPrivateKey(); // call this method to ensure private key is generated
+ $token=$this->getToken();
+ $options=array();
+ $options['publicKey']=$this->getPublicKey();
+ $options['tokenLength']=strlen($token);
+ $options['caseSensitive']=$this->getCaseSensitive();
+ $options['alphabet']=$this->getTokenAlphabet();
+ $options['fontSize']=$this->getTokenFontSize();
+ $options['theme']=$this->getTokenImageTheme();
+ if(($randomSeed=$this->getViewState('RandomSeed',0))===0)
+ {
+ $randomSeed=(int)(microtime()*1000000);
+ $this->setViewState('RandomSeed',$randomSeed);
+ }
+ $options['randomSeed']=$this->getChangingTokenBackground()?0:$randomSeed;
+ $str=serialize($options);
+ return base64_encode(md5($privateKey.$str).$str);
+ }
+
+ /**
+ * @return string the file path of the PHP script generating the token image
+ */
+ protected function getCaptchaScriptFile()
+ {
+ return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'captcha.php';
+ }
+
+ protected function getFontFile()
+ {
+ return dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'verase.ttf';
+ }
+
+ /**
+ * Generates a file with a randomly generated private key.
+ * @return string the path of the file keeping the private key
+ */
+ protected function generatePrivateKeyFile()
+ {
+ $captchaScript=$this->getCaptchaScriptFile();
+ $path=dirname($this->getApplication()->getAssetManager()->getPublishedPath($captchaScript));
+ $fileName=$path.DIRECTORY_SEPARATOR.'captcha_key.php';
+ if(!is_file($fileName))
+ {
+ @mkdir($path);
+ $key=$this->generateRandomKey();
+ $content="<?php
+\$privateKey='$key';
+?>";
+ file_put_contents($fileName,$content);
+ }
+ return $fileName;
+ }
+
+ /**
+ * @return string a randomly generated key
+ */
+ protected function generateRandomKey()
+ {
+ return md5(rand().rand().rand().rand());
+ }
+
+ /**
+ * Generates the token.
+ * @param string public key
+ * @param string private key
+ * @param integer the length of the token
+ * @param boolean whether the token is case sensitive
+ * @return string the token generated.
+ */
+ protected function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
+ {
+ $token=substr($this->hash2string(md5($publicKey.$privateKey),$alphabet).$this->hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
+ return $caseSensitive?$token:strtoupper($token);
+ }
+
+ /**
+ * Converts a hash string into a string with characters consisting of alphanumeric characters.
+ * @param string the hexadecimal representation of the hash string
+ * @param string the alphabet used to represent the converted string. If empty, it means '234578adefhijmnrtwyABDEFGHIJLMNQRTWY', which excludes those confusing characters.
+ * @return string the converted string
+ */
+ protected function hash2string($hex,$alphabet='')
+ {
+ if(strlen($alphabet)<2)
+ $alphabet='234578adefhijmnrtABDEFGHJLMNQRT';
+ $hexLength=strlen($hex);
+ $base=strlen($alphabet);
+ $result='';
+ for($i=0;$i<$hexLength;$i+=6)
+ {
+ $number=hexdec(substr($hex,$i,6));
+ while($number)
+ {
+ $result.=$alphabet[$number%$base];
+ $number=floor($number/$base);
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * Checks the requirements needed for generating CAPTCHA images.
+ * TCaptach requires GD2 with TrueType font support and PNG image support.
+ * @return boolean whether the requirements are satisfied.
+ */
+ public static function checkRequirements()
+ {
+ return extension_loaded('gd') && function_exists('imagettftext') && function_exists('imagepng');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCaptchaValidator.php b/framework/Web/UI/WebControls/TCaptchaValidator.php
index 9eca42fb..23943971 100644
--- a/framework/Web/UI/WebControls/TCaptchaValidator.php
+++ b/framework/Web/UI/WebControls/TCaptchaValidator.php
@@ -1,127 +1,127 @@
-<?php
-/**
- * TCaptchaValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-Prado::using('System.Web.UI.WebControls.TCaptcha');
-
-/**
- * TCaptchaValidator class
- *
- * Notice: while this class is easy to use and implement, it does not provide full security.
- * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
- * A better alternative is provided by {@link TReCaptchaValidator}.
- *
- * TCaptchaValidator validates user input against a CAPTCHA represented by
- * a {@link TCaptcha} control. The input control fails validation if its value
- * is not the same as the token displayed in CAPTCHA. Note, if the user does
- * not enter any thing, it is still considered as failing the validation.
- *
- * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
- * to be the ID path of the input control (usually a {@link TTextBox} control}.
- * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
- * the CAPTCHA control that the user input should be compared with.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TCaptchaValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCaptchaValidator';
- }
-
- /**
- * @return string the ID path of the CAPTCHA control to validate
- */
- public function getCaptchaControl()
- {
- return $this->getViewState('CaptchaControl','');
- }
-
- /**
- * Sets the ID path of the CAPTCHA control to validate.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the validator's naming container to the target control.
- * @param string the ID path
- */
- public function setCaptchaControl($value)
- {
- $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input control has the same value
- * as the one displayed in the corresponding CAPTCHA control.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $value=$this->getValidationValue($this->getValidationTarget());
- $control=$this->findCaptchaControl();
- return $control->validate(trim($value));
- }
-
- /**
- * @return TCaptchaControl the CAPTCHA control to be validated against
- * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
- */
- protected function findCaptchaControl()
- {
- if(($id=$this->getCaptchaControl())==='')
- throw new TConfigurationException('captchavalidator_captchacontrol_required');
- else if(($control=$this->findControl($id))===null)
- throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
- else if(!($control instanceof TCaptcha))
- throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
- else
- return $control;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- $control=$this->findCaptchaControl();
- if($control->getCaseSensitive())
- {
- $options['TokenHash']=$this->generateTokenHash($control->getToken());
- $options['CaseSensitive']=true;
- }
- else
- {
- $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
- $options['CaseSensitive']=false;
- }
- return $options;
- }
-
- private function generateTokenHash($token)
- {
- for($h=0,$i=strlen($token)-1;$i>=0;--$i)
- $h+=ord($token[$i]);
- return $h;
- }
-}
-
+<?php
+/**
+ * TCaptchaValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+Prado::using('System.Web.UI.WebControls.TCaptcha');
+
+/**
+ * TCaptchaValidator class
+ *
+ * Notice: while this class is easy to use and implement, it does not provide full security.
+ * In fact, it's easy to bypass the checks reusing old, already-validated tokens (reply attack).
+ * A better alternative is provided by {@link TReCaptchaValidator}.
+ *
+ * TCaptchaValidator validates user input against a CAPTCHA represented by
+ * a {@link TCaptcha} control. The input control fails validation if its value
+ * is not the same as the token displayed in CAPTCHA. Note, if the user does
+ * not enter any thing, it is still considered as failing the validation.
+ *
+ * To use TCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
+ * to be the ID path of the input control (usually a {@link TTextBox} control}.
+ * Also specify the {@link setCaptchaControl CaptchaControl} to be the ID path of
+ * the CAPTCHA control that the user input should be compared with.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TCaptchaValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCaptchaValidator';
+ }
+
+ /**
+ * @return string the ID path of the CAPTCHA control to validate
+ */
+ public function getCaptchaControl()
+ {
+ return $this->getViewState('CaptchaControl','');
+ }
+
+ /**
+ * Sets the ID path of the CAPTCHA control to validate.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the validator's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setCaptchaControl($value)
+ {
+ $this->setViewState('CaptchaControl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input control has the same value
+ * as the one displayed in the corresponding CAPTCHA control.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $value=$this->getValidationValue($this->getValidationTarget());
+ $control=$this->findCaptchaControl();
+ return $control->validate(trim($value));
+ }
+
+ /**
+ * @return TCaptchaControl the CAPTCHA control to be validated against
+ * @throws TConfigurationException if the CAPTCHA cannot be found according to {@link setCaptchaControl CaptchaControl}
+ */
+ protected function findCaptchaControl()
+ {
+ if(($id=$this->getCaptchaControl())==='')
+ throw new TConfigurationException('captchavalidator_captchacontrol_required');
+ else if(($control=$this->findControl($id))===null)
+ throw new TConfigurationException('captchavalidator_captchacontrol_inexistent',$id);
+ else if(!($control instanceof TCaptcha))
+ throw new TConfigurationException('captchavalidator_captchacontrol_invalid',$id);
+ else
+ return $control;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ $control=$this->findCaptchaControl();
+ if($control->getCaseSensitive())
+ {
+ $options['TokenHash']=$this->generateTokenHash($control->getToken());
+ $options['CaseSensitive']=true;
+ }
+ else
+ {
+ $options['TokenHash']=$this->generateTokenHash(strtoupper($control->getToken()));
+ $options['CaseSensitive']=false;
+ }
+ return $options;
+ }
+
+ private function generateTokenHash($token)
+ {
+ for($h=0,$i=strlen($token)-1;$i>=0;--$i)
+ $h+=ord($token[$i]);
+ return $h;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCheckBox.php b/framework/Web/UI/WebControls/TCheckBox.php
index 641497ac..fe8bfbca 100644
--- a/framework/Web/UI/WebControls/TCheckBox.php
+++ b/framework/Web/UI/WebControls/TCheckBox.php
@@ -1,131 +1,131 @@
-<?php
-/**
- * TCheckBox class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TCheckBox class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TCheckBox class
- *
- * TCheckBox displays a check box on the page.
- * You can specify the caption to display beside the check box by setting
- * the {@link setText Text} property. The caption can appear either on the right
- * or left of the check box, which is determined by the {@link setTextAlign TextAlign}
- * property.
- *
- * To determine whether the TCheckBox component is checked, test the {@link getChecked Checked}
- * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
- * the {@link getChecked Checked} state of the TCheckBox component changes
- * between posts to the server. You can provide an event handler for
- * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
- * control the actions performed when the state of the TCheckBox component changes
- * between posts to the server.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, changing the check box state
- * will cause postback action. And if {@link setCausesValidation CausesValidation}
- * is true, validation will also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
- * that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer, ISurroundable
-{
- private $_dataChanged=false;
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TCheckBox class
+ *
+ * TCheckBox displays a check box on the page.
+ * You can specify the caption to display beside the check box by setting
+ * the {@link setText Text} property. The caption can appear either on the right
+ * or left of the check box, which is determined by the {@link setTextAlign TextAlign}
+ * property.
+ *
+ * To determine whether the TCheckBox component is checked, test the {@link getChecked Checked}
+ * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
+ * the {@link getChecked Checked} state of the TCheckBox component changes
+ * between posts to the server. You can provide an event handler for
+ * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
+ * control the actions performed when the state of the TCheckBox component changes
+ * between posts to the server.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, changing the check box state
+ * will cause postback action. And if {@link setCausesValidation CausesValidation}
+ * is true, validation will also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
+ * that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer, ISurroundable
+{
+ private $_dataChanged=false;
private $_isValid=true;
-
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- $checked=$this->getChecked();
- if($newChecked=isset($values[$key]))
- $this->setValue($values[$key]);
- $this->setChecked($newChecked);
- return $this->_dataChanged=($newChecked!==$checked);
- }
-
- /**
- * Raises postdata changed event.
- * This method raises {@link onCheckedChanged OnCheckedChanged} event.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onCheckedChanged(null);
- }
-
- /**
- * Raises <b>OnCheckedChanged</b> event when {@link getChecked Checked} changes value during postback.
- * If you override this method, be sure to call the parent implementation
- * so that the event delegates can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onCheckedChanged($param)
- {
- $this->raiseEvent('OnCheckedChanged',$this,$param);
- }
-
- /**
- * Registers the checkbox to receive postback data during postback.
- * This is necessary because a checkbox if unchecked, when postback,
- * does not have direct mapping between post data and the checkbox name.
- *
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value of the property that needs validation.
- * @return mixed the property value to be validated
- */
- public function getValidationPropertyValue()
- {
- return $this->getChecked();
- }
-
+
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $checked=$this->getChecked();
+ if($newChecked=isset($values[$key]))
+ $this->setValue($values[$key]);
+ $this->setChecked($newChecked);
+ return $this->_dataChanged=($newChecked!==$checked);
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method raises {@link onCheckedChanged OnCheckedChanged} event.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onCheckedChanged(null);
+ }
+
+ /**
+ * Raises <b>OnCheckedChanged</b> event when {@link getChecked Checked} changes value during postback.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event delegates can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCheckedChanged($param)
+ {
+ $this->raiseEvent('OnCheckedChanged',$this,$param);
+ }
+
+ /**
+ * Registers the checkbox to receive postback data during postback.
+ * This is necessary because a checkbox if unchecked, when postback,
+ * does not have direct mapping between post data and the checkbox name.
+ *
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value of the property that needs validation.
+ * @return mixed the property value to be validated
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getChecked();
+ }
+
/**
* Returns true if this control validated successfully.
* Defaults to true.
@@ -143,390 +143,390 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl
$this->_isValid=TPropertyValue::ensureBoolean($value);
}
- /**
- * @return string the text caption of the checkbox
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the checkbox.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the value of the checkbox. Defaults to empty.
- */
- public function getValue()
- {
- return $this->getViewState('Value','');
- }
-
- /**
- * @param string the value of the checkbox
- */
- public function setValue($value)
- {
- $this->setViewState('Value',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return TTextAlign the alignment (Left or Right) of the text caption, defaults to TTextAlign::Right.
- */
- public function getTextAlign()
- {
- return $this->getViewState('TextAlign',TTextAlign::Right);
- }
-
- /**
- * @param TTextAlign the alignment of the text caption. Valid values include Left and Right.
- */
- public function setTextAlign($value)
- {
- $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
- }
-
- /**
- * @return boolean whether the checkbox is checked
- */
- public function getChecked()
- {
- return $this->getViewState('Checked',false);
- }
-
- /**
- * Sets a value indicating whether the checkbox is to be checked or not.
- * @param boolean whether the checkbox is to be checked or not.
- */
- public function setChecked($value)
- {
- $this->setViewState('Checked',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Returns the value indicating whether the checkbox is checked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getChecked()}.
- * @return boolean whether the checkbox is checked.
- * @see getChecked
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getChecked();
- }
-
- /**
- * Sets the value indicating whether the checkbox is to be checked or not.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setChecked()}.
- * @param boolean whether the checkbox is to be checked
- * @see setChecked
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setChecked($value);
- }
-
- /**
- * @return boolean whether clicking on the checkbox will post the page.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets a value indicating whether clicking on the checkbox will post the page.
- * @param boolean whether clicking on the checkbox will post the page.
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event triggered by this checkbox will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * Sets the value indicating whether postback event trigger by this checkbox will cause input validation.
- * @param boolean whether postback event trigger by this checkbox will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the checkbox causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the checkbox causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the id of the surrounding tag or this clientID if no such tag needed
- */
- public function getSurroundingTagID()
- {
- return $this->getSpanNeeded() ? $this->getClientID().'_parent' : $this->getClientID();
- }
-
- /**
- * Renders the checkbox control.
- * This method overrides the parent implementation by rendering a checkbox input element
- * and a span element if needed.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $this->getPage()->ensureRenderInForm($this);
- if($this->getHasStyle())
- $this->getStyle()->addAttributesToRender($writer);
- if(($tooltip=$this->getToolTip())!=='')
- $writer->addAttribute('title',$tooltip);
- if($this->getHasAttributes())
- {
- $attributes=$this->getAttributes();
- $value=$attributes->remove('value');
- // onclick js should only be added to input tag
- if(($onclick=$attributes->remove('onclick'))===null)
- $onclick='';
- if($attributes->getCount())
- $writer->addAttributes($attributes);
- if($value!==null)
- $attributes->add('value',$value);
- }
- else
- $onclick='';
- if($needspan=$this->getSpanNeeded())
- {
- $writer->addAttribute('id',$this->getSurroundingTagID());
- $writer->renderBeginTag('span');
- }
- $clientID=$this->getClientID();
- if(($text=$this->getText())!=='')
- {
- if($this->getTextAlign()===TTextAlign::Left)
- {
- $this->renderLabel($writer,$clientID,$text);
- $this->renderInputTag($writer,$clientID,$onclick);
- }
- else
- {
- $this->renderInputTag($writer,$clientID,$onclick);
- $this->renderLabel($writer,$clientID,$text);
- }
- }
- else
- $this->renderInputTag($writer,$clientID,$onclick);
- if($needspan)
- $writer->renderEndTag();
- }
-
- /**
- * @return TMap list of attributes to be rendered for label beside the checkbox
- */
- public function getLabelAttributes()
- {
- if($attributes=$this->getViewState('LabelAttributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('LabelAttributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return TMap list of attributes to be rendered for the checkbox
- */
- public function getInputAttributes()
- {
- if($attributes=$this->getViewState('InputAttributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('InputAttributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return string the value attribute to be rendered
- */
- protected function getValueAttribute()
- {
- if(($value=$this->getValue())!=='')
- return $value;
- else
- {
- $attributes=$this->getViewState('InputAttributes',null);
- if($attributes && $attributes->contains('value'))
- return $attributes->itemAt('value');
- else if($this->hasAttribute('value'))
- return $this->getAttribute('value');
- else
- return '';
- }
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Check if we need a span tag to surround this control. The span tag will be created if
- * the Text property is set for this control.
- *
- * @return bool wether this control needs a surrounding span tag
- */
- protected function getSpanNeeded() {
- return $this->getText()!=='';
- }
-
- /**
- * Renders a label beside the checkbox.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string label text
- */
- protected function renderLabel($writer,$clientID,$text)
- {
- $writer->addAttribute('for',$clientID);
- if($attributes=$this->getViewState('LabelAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('label');
- $writer->write($text);
- $writer->renderEndTag();
- }
-
- /**
- * Renders a checkbox input element.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string onclick js
- */
- protected function renderInputTag($writer,$clientID,$onclick)
- {
- if($clientID!=='')
- $writer->addAttribute('id',$clientID);
- $writer->addAttribute('type','checkbox');
- if(($value=$this->getValueAttribute())!=='')
- $writer->addAttribute('value',$value);
- if(!empty($onclick))
- $writer->addAttribute('onclick',$onclick);
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getChecked())
- $writer->addAttribute('checked','checked');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
-
- $page=$this->getPage();
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
-
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- if(($tabindex=$this->getTabIndex())>0)
- $writer->addAttribute('tabindex',"$tabindex");
- if($attributes=$this->getViewState('InputAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCheckBox';
- }
-
- /**
- * Gets the post back options for this checkbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-}
-
-/**
- * TTextAlign class.
- * TTextAlign defines the enumerable type for the possible text alignments
- *
- * The following enumerable values are defined:
- * - Left: left aligned
- * - Right: right aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextAlign extends TEnumerable
-{
- const Left='Left';
- const Right='Right';
-}
-
-?>
+ /**
+ * @return string the text caption of the checkbox
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the checkbox.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the value of the checkbox. Defaults to empty.
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value','');
+ }
+
+ /**
+ * @param string the value of the checkbox
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return TTextAlign the alignment (Left or Right) of the text caption, defaults to TTextAlign::Right.
+ */
+ public function getTextAlign()
+ {
+ return $this->getViewState('TextAlign',TTextAlign::Right);
+ }
+
+ /**
+ * @param TTextAlign the alignment of the text caption. Valid values include Left and Right.
+ */
+ public function setTextAlign($value)
+ {
+ $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
+ }
+
+ /**
+ * @return boolean whether the checkbox is checked
+ */
+ public function getChecked()
+ {
+ return $this->getViewState('Checked',false);
+ }
+
+ /**
+ * Sets a value indicating whether the checkbox is to be checked or not.
+ * @param boolean whether the checkbox is to be checked or not.
+ */
+ public function setChecked($value)
+ {
+ $this->setViewState('Checked',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Returns the value indicating whether the checkbox is checked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getChecked()}.
+ * @return boolean whether the checkbox is checked.
+ * @see getChecked
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getChecked();
+ }
+
+ /**
+ * Sets the value indicating whether the checkbox is to be checked or not.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setChecked()}.
+ * @param boolean whether the checkbox is to be checked
+ * @see setChecked
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setChecked($value);
+ }
+
+ /**
+ * @return boolean whether clicking on the checkbox will post the page.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets a value indicating whether clicking on the checkbox will post the page.
+ * @param boolean whether clicking on the checkbox will post the page.
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event triggered by this checkbox will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * Sets the value indicating whether postback event trigger by this checkbox will cause input validation.
+ * @param boolean whether postback event trigger by this checkbox will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the checkbox causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the checkbox causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the id of the surrounding tag or this clientID if no such tag needed
+ */
+ public function getSurroundingTagID()
+ {
+ return $this->getSpanNeeded() ? $this->getClientID().'_parent' : $this->getClientID();
+ }
+
+ /**
+ * Renders the checkbox control.
+ * This method overrides the parent implementation by rendering a checkbox input element
+ * and a span element if needed.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->getPage()->ensureRenderInForm($this);
+ if($this->getHasStyle())
+ $this->getStyle()->addAttributesToRender($writer);
+ if(($tooltip=$this->getToolTip())!=='')
+ $writer->addAttribute('title',$tooltip);
+ if($this->getHasAttributes())
+ {
+ $attributes=$this->getAttributes();
+ $value=$attributes->remove('value');
+ // onclick js should only be added to input tag
+ if(($onclick=$attributes->remove('onclick'))===null)
+ $onclick='';
+ if($attributes->getCount())
+ $writer->addAttributes($attributes);
+ if($value!==null)
+ $attributes->add('value',$value);
+ }
+ else
+ $onclick='';
+ if($needspan=$this->getSpanNeeded())
+ {
+ $writer->addAttribute('id',$this->getSurroundingTagID());
+ $writer->renderBeginTag('span');
+ }
+ $clientID=$this->getClientID();
+ if(($text=$this->getText())!=='')
+ {
+ if($this->getTextAlign()===TTextAlign::Left)
+ {
+ $this->renderLabel($writer,$clientID,$text);
+ $this->renderInputTag($writer,$clientID,$onclick);
+ }
+ else
+ {
+ $this->renderInputTag($writer,$clientID,$onclick);
+ $this->renderLabel($writer,$clientID,$text);
+ }
+ }
+ else
+ $this->renderInputTag($writer,$clientID,$onclick);
+ if($needspan)
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return TMap list of attributes to be rendered for label beside the checkbox
+ */
+ public function getLabelAttributes()
+ {
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('LabelAttributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return TMap list of attributes to be rendered for the checkbox
+ */
+ public function getInputAttributes()
+ {
+ if($attributes=$this->getViewState('InputAttributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('InputAttributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return string the value attribute to be rendered
+ */
+ protected function getValueAttribute()
+ {
+ if(($value=$this->getValue())!=='')
+ return $value;
+ else
+ {
+ $attributes=$this->getViewState('InputAttributes',null);
+ if($attributes && $attributes->contains('value'))
+ return $attributes->itemAt('value');
+ else if($this->hasAttribute('value'))
+ return $this->getAttribute('value');
+ else
+ return '';
+ }
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Check if we need a span tag to surround this control. The span tag will be created if
+ * the Text property is set for this control.
+ *
+ * @return bool wether this control needs a surrounding span tag
+ */
+ protected function getSpanNeeded() {
+ return $this->getText()!=='';
+ }
+
+ /**
+ * Renders a label beside the checkbox.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string label text
+ */
+ protected function renderLabel($writer,$clientID,$text)
+ {
+ $writer->addAttribute('for',$clientID);
+ if($attributes=$this->getViewState('LabelAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('label');
+ $writer->write($text);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders a checkbox input element.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ if($clientID!=='')
+ $writer->addAttribute('id',$clientID);
+ $writer->addAttribute('type','checkbox');
+ if(($value=$this->getValueAttribute())!=='')
+ $writer->addAttribute('value',$value);
+ if(!empty($onclick))
+ $writer->addAttribute('onclick',$onclick);
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getChecked())
+ $writer->addAttribute('checked','checked');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+
+ $page=$this->getPage();
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ if(($tabindex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabindex");
+ if($attributes=$this->getViewState('InputAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCheckBox';
+ }
+
+ /**
+ * Gets the post back options for this checkbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+}
+
+/**
+ * TTextAlign class.
+ * TTextAlign defines the enumerable type for the possible text alignments
+ *
+ * The following enumerable values are defined:
+ * - Left: left aligned
+ * - Right: right aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextAlign extends TEnumerable
+{
+ const Left='Left';
+ const Right='Right';
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TCheckBoxColumn.php b/framework/Web/UI/WebControls/TCheckBoxColumn.php
index 9c1db114..e1a2e178 100644
--- a/framework/Web/UI/WebControls/TCheckBoxColumn.php
+++ b/framework/Web/UI/WebControls/TCheckBoxColumn.php
@@ -1,123 +1,123 @@
-<?php
-/**
- * TCheckBoxColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TCheckBoxColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-/**
- * TCheckBox class file
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-
-/**
- * TCheckBoxColumn class
- *
- * TCheckBoxColumn represents a checkbox column that is bound to a field in a data source.
- * The checked state of the checkboxes are determiend by the bound data at
- * {@link setDataField DataField}. If {@link setReadOnly ReadOnly} is false,
- * TCheckBoxColumn will display an enabled checkbox provided the cells are
- * in edit mode. Otherwise, the checkboxes will be disabled to prevent from editting.
- *
- * The checkbox control in the TCheckBoxColumn can be accessed by one of
- * the following two methods:
- * <code>
- * $datagridItem->CheckBoxColumnID->CheckBox
- * $datagridItem->CheckBoxColumnID->Controls[0]
- * </code>
- * The second method is possible because the checkbox control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBoxColumn extends TDataGridColumn
-{
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a checkbox inside the cell.
- * If the column is read-only or if the item is not in edit mode,
- * the checkbox will be set disabled.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $checkBox=new TCheckBox;
- if($this->getReadOnly() || $itemType!==TListItemType::EditItem)
- $checkBox->setEnabled(false);
- $cell->setHorizontalAlign('Center');
- $cell->getControls()->add($checkBox);
- $cell->registerObject('CheckBox',$checkBox);
- if($this->getDataField()!=='')
- $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($field=$this->getDataField())!=='')
- $value=TPropertyValue::ensureBoolean($this->getDataFieldValue($data,$field));
- else
- $value=TPropertyValue::ensureBoolean($data);
- if($sender instanceof TCheckBox)
- $sender->setChecked($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+/**
+ * TCheckBox class file
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+
+/**
+ * TCheckBoxColumn class
+ *
+ * TCheckBoxColumn represents a checkbox column that is bound to a field in a data source.
+ * The checked state of the checkboxes are determiend by the bound data at
+ * {@link setDataField DataField}. If {@link setReadOnly ReadOnly} is false,
+ * TCheckBoxColumn will display an enabled checkbox provided the cells are
+ * in edit mode. Otherwise, the checkboxes will be disabled to prevent from editting.
+ *
+ * The checkbox control in the TCheckBoxColumn can be accessed by one of
+ * the following two methods:
+ * <code>
+ * $datagridItem->CheckBoxColumnID->CheckBox
+ * $datagridItem->CheckBoxColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the checkbox control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBoxColumn extends TDataGridColumn
+{
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a checkbox inside the cell.
+ * If the column is read-only or if the item is not in edit mode,
+ * the checkbox will be set disabled.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $checkBox=new TCheckBox;
+ if($this->getReadOnly() || $itemType!==TListItemType::EditItem)
+ $checkBox->setEnabled(false);
+ $cell->setHorizontalAlign('Center');
+ $cell->getControls()->add($checkBox);
+ $cell->registerObject('CheckBox',$checkBox);
+ if($this->getDataField()!=='')
+ $checkBox->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($field=$this->getDataField())!=='')
+ $value=TPropertyValue::ensureBoolean($this->getDataFieldValue($data,$field));
+ else
+ $value=TPropertyValue::ensureBoolean($data);
+ if($sender instanceof TCheckBox)
+ $sender->setChecked($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCheckBoxList.php b/framework/Web/UI/WebControls/TCheckBoxList.php
index 2f938174..3c298a02 100644
--- a/framework/Web/UI/WebControls/TCheckBoxList.php
+++ b/framework/Web/UI/WebControls/TCheckBoxList.php
@@ -1,499 +1,499 @@
-<?php
-/**
- * TCheckBoxList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-/**
- * Includes TRepeatInfo class
- */
-Prado::using('System.Web.UI.WebControls.TRepeatInfo');
-/**
- * Includes TCheckBox class
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-
-/**
- * TCheckBoxList class
- *
- * TCheckBoxList displays a list of checkboxes on a Web page.
- *
- * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout},
- * which can be either 'Table' (default) or 'Flow'.
- * A table layout uses HTML table cells to organize the checkboxes while
- * a flow layout uses line breaks to organize the checkboxes.
- * When the layout is using 'Table', {@link setCellPadding CellPadding} and
- * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and
- * cellpadding of the table.
- *
- * The number of columns used to display the checkboxes is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- *
- * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler, IValidatable
-{
- private $_repeatedControl;
- private $_isEnabled;
- private $_changedEventRaised=false;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * Constructor.
- * Remember to call parent implementation if you override this method
- */
- public function __construct()
- {
- parent::__construct();
- $this->_repeatedControl=$this->createRepeatedControl();
- $this->_repeatedControl->setEnableViewState(false);
- $this->_repeatedControl->setID('c0');
- $this->getControls()->add($this->_repeatedControl);
- }
-
- /**
- * Creates a control used for repetition (used as a template).
- * @return TControl the control to be repeated
- */
- protected function createRepeatedControl()
- {
- return new TCheckBox;
- }
-
- /**
- * Finds a control by ID.
- * This method overrides the parent implementation so that it always returns
- * the checkbox list itself (because the checkbox list does not have child controls.)
- * @param string control ID
- * @return TControl control being found
- */
- public function findControl($id)
- {
- return $this;
- }
-
- /**
- * @return boolean whether this control supports multiple selection. Always true for checkbox list.
- */
- protected function getIsMultiSelect()
- {
- return true;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by checkbox list.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return TTextAlign the alignment of the text caption, defaults to TTextAlign::Right.
- */
- public function getTextAlign()
- {
- return $this->getViewState('TextAlign',TTextAlign::Right);
- }
-
- /**
- * @param TTextAlign the text alignment of the checkboxes
- */
- public function setTextAlign($value)
- {
- $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
- }
-
-
- /**
- * @return TRepeatInfo repeat information (primarily used by control developers)
- */
- protected function getRepeatInfo()
- {
- if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
- {
- $repeatInfo=new TRepeatInfo;
- $this->setViewState('RepeatInfo',$repeatInfo,null);
- }
- return $repeatInfo;
- }
-
- /**
- * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->getRepeatInfo()->getRepeatColumns();
- }
-
- /**
- * @param integer the number of columns that the list should be displayed with.
- */
- public function setRepeatColumns($value)
- {
- $this->getRepeatInfo()->setRepeatColumns($value);
- }
-
- /**
- * @return string the direction of traversing the list, defaults to 'Vertical'
- */
- public function getRepeatDirection()
- {
- return $this->getRepeatInfo()->getRepeatDirection();
- }
-
- /**
- * @param string the direction (Vertical, Horizontal) of traversing the list
- */
- public function setRepeatDirection($value)
- {
- $this->getRepeatInfo()->setRepeatDirection($value);
- }
-
- /**
- * @return string how the list should be displayed, using table or using line breaks. Defaults to 'Table'.
- */
- public function getRepeatLayout()
- {
- return $this->getRepeatInfo()->getRepeatLayout();
- }
-
- /**
- * @param string how the list should be displayed, using table or using line breaks (Table, Flow)
- */
- public function setRepeatLayout($value)
- {
- $this->getRepeatInfo()->setRepeatLayout($value);
- }
-
- /**
- * @return integer the cellspacing for the table keeping the checkbox list. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * Sets the cellspacing for the table keeping the checkbox list.
- * @param integer the cellspacing for the table keeping the checkbox list.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table keeping the checkbox list. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * Sets the cellpadding for the table keeping the checkbox list.
- * @param integer the cellpadding for the table keeping the checkbox list.
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * Returns a value indicating whether this control contains header item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasHeader()
- {
- return false;
- }
-
- /**
- * Returns a value indicating whether this control contains footer item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasFooter()
- {
- return false;
- }
-
- /**
- * Returns a value indicating whether this control contains separator items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasSeparators()
- {
- return false;
- }
-
- /**
- * @param boolean whether the control is to be enabled.
- */
- public function setEnabled($value)
- {
- parent::setEnabled($value);
- $value = !TPropertyValue::ensureBoolean($value);
- // if this is an active control,
- // and it's a callback,
- // and we can update clientside,
- // then update the 'disabled' attribute of the items.
- if(($this instanceof IActiveControl) &&
- $this->getPage()->getIsCallBack() &&
- $this->getActiveControl()->canUpdateClientSide())
- {
- $items = $this->getItems();
- $cs = $this->getPage()->getCallbackClient();
- $baseClientID = $this->getClientID().'_c';
- foreach($items as $index=>$item)
- {
- $cs->setAttribute($baseClientID.$index, 'disabled', $value);
- }
- }
- }
-
- /**
- * Returns a style used for rendering items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer index of the item being rendered
- * @return null
- */
- public function generateItemStyle($itemType,$index)
- {
- return null;
- }
-
- /**
- * Renders an item in the list.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param THtmlWriter writer for rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the item in the item list
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index)
- {
- $repeatedControl=$this->_repeatedControl;
- $item=$this->getItems()->itemAt($index);
- if($item->getHasAttributes())
- $repeatedControl->getAttributes()->copyFrom($item->getAttributes());
- else if($repeatedControl->getHasAttributes())
- $repeatedControl->getAttributes()->clear();
- $repeatedControl->setID("c$index");
- $repeatedControl->setText($item->getText());
- $repeatedControl->setChecked($item->getSelected());
- $repeatedControl->setAttribute('value',$item->getValue());
- $repeatedControl->setEnabled($this->_isEnabled && $item->getEnabled());
- $repeatedControl->setEnableClientScript(false);
- $repeatedControl->renderControl($writer);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if($this->getEnabled(true))
- {
- $index=(int)substr($key,strlen($this->getUniqueID())+2);
- $this->ensureDataBound();
- if($index>=0 && $index<$this->getItemCount())
- {
- $item=$this->getItems()->itemAt($index);
- if($item->getEnabled())
- {
- $checked=isset($values[$key]);
- if($item->getSelected()!==$checked)
- {
- $item->setSelected($checked);
- if(!$this->_changedEventRaised)
- {
- $this->_changedEventRaised=true;
- return $this->_dataChanged=true;
- }
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Registers for post data on postback.
- * This method overrides the parent implementation.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->_repeatedControl->setAutoPostBack($this->getAutoPostBack());
- $this->_repeatedControl->setCausesValidation($this->getCausesValidation());
- $this->_repeatedControl->setValidationGroup($this->getValidationGroup());
- $page=$this->getPage();
- $n=$this->getItemCount();
- for($i=0;$i<$n;++$i)
- {
- $this->_repeatedControl->setID("c$i");
- $page->registerRequiresPostData($this->_repeatedControl);
- }
- }
-
- /**
- * Wether the list should be rendered inside a span or not
- *
- *@return boolean true if we need a span
- */
- protected function getSpanNeeded ()
- {
- return $this->getRepeatLayout()===TRepeatLayout::Raw;
- }
-
- /**
- * Renders the checkbox list control.
- * This method overrides the parent implementation.
- * @param THtmlWriter writer for rendering purpose.
- */
- public function render($writer)
- {
- if($this->getItemCount()>0)
- {
- if ($needSpan=$this->getSpanNeeded())
- {
- $writer->addAttribute('id', $this->getClientId());
- $writer->renderBeginTag('span');
- }
- $this->_isEnabled=$this->getEnabled(true);
- $repeatInfo=$this->getRepeatInfo();
- $accessKey=$this->getAccessKey();
- $tabIndex=$this->getTabIndex();
- $this->_repeatedControl->setTextAlign($this->getTextAlign());
- $this->_repeatedControl->setAccessKey($accessKey);
- $this->_repeatedControl->setTabIndex($tabIndex);
- $this->setAccessKey('');
- $this->setTabIndex(0);
- $repeatInfo->renderRepeater($writer,$this);
- $this->setAccessKey($accessKey);
- $this->setTabIndex($tabIndex);
- if ($needSpan)
- $writer->renderEndTag();
- }
- //checkbox skipped the client control script in addAttributesToRender
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $this->getPage()->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCheckBoxList';
- }
-
- /**
- * Gets the post back options for this checkbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ListID'] = $this->getClientID();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ListName'] = $this->getUniqueID();
- $options['ItemCount'] = $this->getItemCount();
- return $options;
- }
-
-}
-
+<?php
+/**
+ * TCheckBoxList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+/**
+ * Includes TRepeatInfo class
+ */
+Prado::using('System.Web.UI.WebControls.TRepeatInfo');
+/**
+ * Includes TCheckBox class
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+
+/**
+ * TCheckBoxList class
+ *
+ * TCheckBoxList displays a list of checkboxes on a Web page.
+ *
+ * The layout of the checkbox list is specified via {@link setRepeatLayout RepeatLayout},
+ * which can be either 'Table' (default) or 'Flow'.
+ * A table layout uses HTML table cells to organize the checkboxes while
+ * a flow layout uses line breaks to organize the checkboxes.
+ * When the layout is using 'Table', {@link setCellPadding CellPadding} and
+ * {@link setCellSpacing CellSpacing} can be used to adjust the cellpadding and
+ * cellpadding of the table.
+ *
+ * The number of columns used to display the checkboxes is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ *
+ * The alignment of the text besides each checkbox can be specified via {@link setTextAlign TextAlign}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler, IValidatable
+{
+ private $_repeatedControl;
+ private $_isEnabled;
+ private $_changedEventRaised=false;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Constructor.
+ * Remember to call parent implementation if you override this method
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->_repeatedControl=$this->createRepeatedControl();
+ $this->_repeatedControl->setEnableViewState(false);
+ $this->_repeatedControl->setID('c0');
+ $this->getControls()->add($this->_repeatedControl);
+ }
+
+ /**
+ * Creates a control used for repetition (used as a template).
+ * @return TControl the control to be repeated
+ */
+ protected function createRepeatedControl()
+ {
+ return new TCheckBox;
+ }
+
+ /**
+ * Finds a control by ID.
+ * This method overrides the parent implementation so that it always returns
+ * the checkbox list itself (because the checkbox list does not have child controls.)
+ * @param string control ID
+ * @return TControl control being found
+ */
+ public function findControl($id)
+ {
+ return $this;
+ }
+
+ /**
+ * @return boolean whether this control supports multiple selection. Always true for checkbox list.
+ */
+ protected function getIsMultiSelect()
+ {
+ return true;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by checkbox list.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return TTextAlign the alignment of the text caption, defaults to TTextAlign::Right.
+ */
+ public function getTextAlign()
+ {
+ return $this->getViewState('TextAlign',TTextAlign::Right);
+ }
+
+ /**
+ * @param TTextAlign the text alignment of the checkboxes
+ */
+ public function setTextAlign($value)
+ {
+ $this->setViewState('TextAlign',TPropertyValue::ensureEnum($value,'TTextAlign'),TTextAlign::Right);
+ }
+
+
+ /**
+ * @return TRepeatInfo repeat information (primarily used by control developers)
+ */
+ protected function getRepeatInfo()
+ {
+ if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
+ {
+ $repeatInfo=new TRepeatInfo;
+ $this->setViewState('RepeatInfo',$repeatInfo,null);
+ }
+ return $repeatInfo;
+ }
+
+ /**
+ * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->getRepeatInfo()->getRepeatColumns();
+ }
+
+ /**
+ * @param integer the number of columns that the list should be displayed with.
+ */
+ public function setRepeatColumns($value)
+ {
+ $this->getRepeatInfo()->setRepeatColumns($value);
+ }
+
+ /**
+ * @return string the direction of traversing the list, defaults to 'Vertical'
+ */
+ public function getRepeatDirection()
+ {
+ return $this->getRepeatInfo()->getRepeatDirection();
+ }
+
+ /**
+ * @param string the direction (Vertical, Horizontal) of traversing the list
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->getRepeatInfo()->setRepeatDirection($value);
+ }
+
+ /**
+ * @return string how the list should be displayed, using table or using line breaks. Defaults to 'Table'.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->getRepeatInfo()->getRepeatLayout();
+ }
+
+ /**
+ * @param string how the list should be displayed, using table or using line breaks (Table, Flow)
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->getRepeatInfo()->setRepeatLayout($value);
+ }
+
+ /**
+ * @return integer the cellspacing for the table keeping the checkbox list. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * Sets the cellspacing for the table keeping the checkbox list.
+ * @param integer the cellspacing for the table keeping the checkbox list.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table keeping the checkbox list. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * Sets the cellpadding for the table keeping the checkbox list.
+ * @param integer the cellpadding for the table keeping the checkbox list.
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * Returns a value indicating whether this control contains header item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasHeader()
+ {
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether this control contains footer item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasFooter()
+ {
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether this control contains separator items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasSeparators()
+ {
+ return false;
+ }
+
+ /**
+ * @param boolean whether the control is to be enabled.
+ */
+ public function setEnabled($value)
+ {
+ parent::setEnabled($value);
+ $value = !TPropertyValue::ensureBoolean($value);
+ // if this is an active control,
+ // and it's a callback,
+ // and we can update clientside,
+ // then update the 'disabled' attribute of the items.
+ if(($this instanceof IActiveControl) &&
+ $this->getPage()->getIsCallBack() &&
+ $this->getActiveControl()->canUpdateClientSide())
+ {
+ $items = $this->getItems();
+ $cs = $this->getPage()->getCallbackClient();
+ $baseClientID = $this->getClientID().'_c';
+ foreach($items as $index=>$item)
+ {
+ $cs->setAttribute($baseClientID.$index, 'disabled', $value);
+ }
+ }
+ }
+
+ /**
+ * Returns a style used for rendering items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer index of the item being rendered
+ * @return null
+ */
+ public function generateItemStyle($itemType,$index)
+ {
+ return null;
+ }
+
+ /**
+ * Renders an item in the list.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param THtmlWriter writer for rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the item in the item list
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index)
+ {
+ $repeatedControl=$this->_repeatedControl;
+ $item=$this->getItems()->itemAt($index);
+ if($item->getHasAttributes())
+ $repeatedControl->getAttributes()->copyFrom($item->getAttributes());
+ else if($repeatedControl->getHasAttributes())
+ $repeatedControl->getAttributes()->clear();
+ $repeatedControl->setID("c$index");
+ $repeatedControl->setText($item->getText());
+ $repeatedControl->setChecked($item->getSelected());
+ $repeatedControl->setAttribute('value',$item->getValue());
+ $repeatedControl->setEnabled($this->_isEnabled && $item->getEnabled());
+ $repeatedControl->setEnableClientScript(false);
+ $repeatedControl->renderControl($writer);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if($this->getEnabled(true))
+ {
+ $index=(int)substr($key,strlen($this->getUniqueID())+2);
+ $this->ensureDataBound();
+ if($index>=0 && $index<$this->getItemCount())
+ {
+ $item=$this->getItems()->itemAt($index);
+ if($item->getEnabled())
+ {
+ $checked=isset($values[$key]);
+ if($item->getSelected()!==$checked)
+ {
+ $item->setSelected($checked);
+ if(!$this->_changedEventRaised)
+ {
+ $this->_changedEventRaised=true;
+ return $this->_dataChanged=true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Registers for post data on postback.
+ * This method overrides the parent implementation.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->_repeatedControl->setAutoPostBack($this->getAutoPostBack());
+ $this->_repeatedControl->setCausesValidation($this->getCausesValidation());
+ $this->_repeatedControl->setValidationGroup($this->getValidationGroup());
+ $page=$this->getPage();
+ $n=$this->getItemCount();
+ for($i=0;$i<$n;++$i)
+ {
+ $this->_repeatedControl->setID("c$i");
+ $page->registerRequiresPostData($this->_repeatedControl);
+ }
+ }
+
+ /**
+ * Wether the list should be rendered inside a span or not
+ *
+ *@return boolean true if we need a span
+ */
+ protected function getSpanNeeded ()
+ {
+ return $this->getRepeatLayout()===TRepeatLayout::Raw;
+ }
+
+ /**
+ * Renders the checkbox list control.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getItemCount()>0)
+ {
+ if ($needSpan=$this->getSpanNeeded())
+ {
+ $writer->addAttribute('id', $this->getClientId());
+ $writer->renderBeginTag('span');
+ }
+ $this->_isEnabled=$this->getEnabled(true);
+ $repeatInfo=$this->getRepeatInfo();
+ $accessKey=$this->getAccessKey();
+ $tabIndex=$this->getTabIndex();
+ $this->_repeatedControl->setTextAlign($this->getTextAlign());
+ $this->_repeatedControl->setAccessKey($accessKey);
+ $this->_repeatedControl->setTabIndex($tabIndex);
+ $this->setAccessKey('');
+ $this->setTabIndex(0);
+ $repeatInfo->renderRepeater($writer,$this);
+ $this->setAccessKey($accessKey);
+ $this->setTabIndex($tabIndex);
+ if ($needSpan)
+ $writer->renderEndTag();
+ }
+ //checkbox skipped the client control script in addAttributesToRender
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $this->getPage()->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCheckBoxList';
+ }
+
+ /**
+ * Gets the post back options for this checkbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ListID'] = $this->getClientID();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ListName'] = $this->getUniqueID();
+ $options['ItemCount'] = $this->getItemCount();
+ return $options;
+ }
+
+}
+
diff --git a/framework/Web/UI/WebControls/TColorPicker.php b/framework/Web/UI/WebControls/TColorPicker.php
index e5b24bd0..365421a1 100644
--- a/framework/Web/UI/WebControls/TColorPicker.php
+++ b/framework/Web/UI/WebControls/TColorPicker.php
@@ -1,290 +1,290 @@
-<?php
-/**
- * TColorPicker class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TColorPicker class.
- *
- * TColorPicker displays a text box for color input purpose.
- * Next to the textbox there's a button filled with the current chosen color.
- * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF).
- * Alternatively, if the <b>ShowColorPicker</b> property is enabled (it is by default), users can click the button
- * to have a color picker UI appear. A color chan be chosen directly by clicking on the color picker.
- *
- * TColorPicker has three different color picker UI <b>Mode</b>s:
- * # <b>Simple</b> - Grid with 12 simple colors.
- * # <b>Basic</b> - Grid with the most common 70 colors. This is the default mode.
- * # <b>Full</b> - Full-featured color picker.
- *
- * The <b>CssClass</b> property can be used to override the CSS class name
- * for the color picker panel. The <b>ColorStyle</b> property sets the packages
- * styles available. E.g. <b>default</b>.
- *
- * If the <b>Mode</b> property is set to <b>Full</b>, the color picker panel will
- * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the <b>OKButtonText</b>
- * and <b>CancelButtonText</b> properties.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TColorPicker extends TTextBox
-{
- const SCRIPT_PATH = 'prado/colorpicker';
-
- private $_clientSide;
-
- /**
- * @return boolean whether the color picker should pop up when the button is clicked.
- */
- public function getShowColorPicker()
- {
- return $this->getViewState('ShowColorPicker',true);
- }
-
- /**
- * Sets whether to pop up the color picker when the button is clicked.
- * @param boolean whether to show the color picker popup
- */
- public function setShowColorPicker($value)
- {
- $this->setViewState('ShowColorPicker',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @param TColorPickerMode color picker UI mode
- */
- public function setMode($value)
- {
- $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TColorPickerMode'), TColorPickerMode::Basic);
- }
-
- /**
- * @return TColorPickerMode current color picker UI mode. Defaults to TColorPickerMode::Basic.
- */
- public function getMode()
- {
- return $this->getViewState('Mode', TColorPickerMode::Basic);
- }
-
- /**
- * @param string set the color picker style
- */
- public function setColorPickerStyle($value)
- {
- $this->setViewState('ColorStyle', $value, 'default');
- }
-
- /**
- * @return string current color picker style
- */
- public function getColorPickerStyle()
- {
- return $this->getViewState('ColorStyle', 'default');
- }
-
- /**
- * @return string text for the color picker OK button. Default is "OK".
- */
- public function getOKButtonText()
- {
- return $this->getViewState('OKButtonText', 'OK');
- }
-
- /**
- * @param string text for the color picker OK button
- */
- public function setOKButtonText($value)
- {
- $this->setViewState('OKButtonText', $value, 'OK');
- }
-
- /**
- * @return string text for the color picker Cancel button. Default is "Cancel".
- */
- public function getCancelButtonText()
- {
- return $this->getViewState('CancelButtonText', 'Cancel');
- }
-
- /**
- * @param string text for the color picker Cancel button
- */
- public function setCancelButtonText($value)
- {
- $this->setViewState('CancelButtonText', $value, 'Cancel');
- }
-
- /**
- * @return TColorPickerClientSide javascript event options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientSide();
- return $this->_clientSide;
- }
-
- /**
- * @return TColorPickerClientSide javascript validator event options.
- */
- protected function createClientSide()
- {
- return new TColorPickerClientSide;
- }
-
- /**
- * Get javascript color picker options.
- * @return array color picker client-side options
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['ClassName'] = $this->getCssClass();
- $options['ShowColorPicker'] = $this->getShowColorPicker();
- if($options['ShowColorPicker'])
- {
- $mode = $this->getMode();
- if($mode == TColorPickerMode::Full) $options['Mode'] = $mode;
- else if($mode == TColorPickerMode::Simple) $options['Palette'] = 'Tiny';
- $options['OKButtonText'] = $this->getOKButtonText();
- $options['CancelButtonText'] = $this->getCancelButtonText();
- }
- $options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
- return $options;
- }
-
- /**
- * @param string asset file in the self::SCRIPT_PATH directory.
- * @return string asset file url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Publish the color picker Css asset files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->publishColorPickerAssets();
- }
-
- /**
- * Publish the color picker assets.
- */
- protected function publishColorPickerAssets()
- {
- $cs = $this->getPage()->getClientScript();
- $key = "prado:".get_class($this);
- $imgs['button.gif'] = $this->getAssetUrl('button.gif');
- $imgs['background.png'] = $this->getAssetUrl('background.png');
- $options = TJavaScript::encode($imgs);
- $code = "Prado.WebUI.TColorPicker.UIImages = {$options};";
- $cs->registerEndScript($key, $code);
- $cs->registerPradoScript("colorpicker");
- $url = $this->getAssetUrl($this->getColorPickerStyle().'.css');
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- }
-
- /**
- * Renders additional body content.
- * This method overrides parent implementation by adding
- * additional color picker button.
- * @param THtmlWriter writer
- */
- public function renderEndTag($writer)
- {
- parent::renderEndTag($writer);
-
- $color = $this->getText();
- $writer->addAttribute('class', 'TColorPicker_button');
- $writer->renderBeginTag('span');
-
- $writer->addAttribute('id', $this->getClientID().'_button');
- $writer->addAttribute('src', $this->getAssetUrl('button.gif'));
- if($color !== '')
- $writer->addAttribute('style', "background-color:{$color};");
- $writer->addAttribute('width', '20');
- $writer->addAttribute('height', '20');
- $writer->addAttribute('alt', '');
- $writer->renderBeginTag('img');
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TColorPicker';
- }
-}
-
-/**
- * TColorPickerMode class.
- * TColorPickerMode defines the enumerable type for the possible UI mode
- * that a {@link TColorPicker} control can take.
- *
- * The following enumerable values are defined:
- * # Simple - Grid with 12 simple colors.
- * # Basic - Grid with the most common 70 colors. This is the default mode.
- * # Full - Full-featured color picker.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TColorPickerMode extends TEnumerable
-{
- const Simple='Simple';
- const Basic='Basic';
- const Full='Full';
-}
-
-/**
- * TColorPickerClientSide class.
- *
- * Client-side javascript code options.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TColorPickerClientSide extends TClientSideOptions
-{
- /**
- * @return string javascript code for when a color is selected.
- */
- public function getOnColorSelected()
- {
- return $this->getOption('OnColorSelected');
- }
-
- /**
- * @param string javascript code for when a color is selected.
- */
- public function setOnColorSelected($javascript)
- {
- $this->setFunction('OnColorSelected', $javascript);
- }
-}
-
+<?php
+/**
+ * TColorPicker class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TColorPicker class.
+ *
+ * TColorPicker displays a text box for color input purpose.
+ * Next to the textbox there's a button filled with the current chosen color.
+ * Users can write a color name directly in the text box as an hex triplet (also known as HTML notation, eg: #FF00FF).
+ * Alternatively, if the <b>ShowColorPicker</b> property is enabled (it is by default), users can click the button
+ * to have a color picker UI appear. A color chan be chosen directly by clicking on the color picker.
+ *
+ * TColorPicker has three different color picker UI <b>Mode</b>s:
+ * # <b>Simple</b> - Grid with 12 simple colors.
+ * # <b>Basic</b> - Grid with the most common 70 colors. This is the default mode.
+ * # <b>Full</b> - Full-featured color picker.
+ *
+ * The <b>CssClass</b> property can be used to override the CSS class name
+ * for the color picker panel. The <b>ColorStyle</b> property sets the packages
+ * styles available. E.g. <b>default</b>.
+ *
+ * If the <b>Mode</b> property is set to <b>Full</b>, the color picker panel will
+ * display an "Ok" and "Cancel" buttons. You can customize the button labels setting the <b>OKButtonText</b>
+ * and <b>CancelButtonText</b> properties.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TColorPicker extends TTextBox
+{
+ const SCRIPT_PATH = 'prado/colorpicker';
+
+ private $_clientSide;
+
+ /**
+ * @return boolean whether the color picker should pop up when the button is clicked.
+ */
+ public function getShowColorPicker()
+ {
+ return $this->getViewState('ShowColorPicker',true);
+ }
+
+ /**
+ * Sets whether to pop up the color picker when the button is clicked.
+ * @param boolean whether to show the color picker popup
+ */
+ public function setShowColorPicker($value)
+ {
+ $this->setViewState('ShowColorPicker',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @param TColorPickerMode color picker UI mode
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TColorPickerMode'), TColorPickerMode::Basic);
+ }
+
+ /**
+ * @return TColorPickerMode current color picker UI mode. Defaults to TColorPickerMode::Basic.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode', TColorPickerMode::Basic);
+ }
+
+ /**
+ * @param string set the color picker style
+ */
+ public function setColorPickerStyle($value)
+ {
+ $this->setViewState('ColorStyle', $value, 'default');
+ }
+
+ /**
+ * @return string current color picker style
+ */
+ public function getColorPickerStyle()
+ {
+ return $this->getViewState('ColorStyle', 'default');
+ }
+
+ /**
+ * @return string text for the color picker OK button. Default is "OK".
+ */
+ public function getOKButtonText()
+ {
+ return $this->getViewState('OKButtonText', 'OK');
+ }
+
+ /**
+ * @param string text for the color picker OK button
+ */
+ public function setOKButtonText($value)
+ {
+ $this->setViewState('OKButtonText', $value, 'OK');
+ }
+
+ /**
+ * @return string text for the color picker Cancel button. Default is "Cancel".
+ */
+ public function getCancelButtonText()
+ {
+ return $this->getViewState('CancelButtonText', 'Cancel');
+ }
+
+ /**
+ * @param string text for the color picker Cancel button
+ */
+ public function setCancelButtonText($value)
+ {
+ $this->setViewState('CancelButtonText', $value, 'Cancel');
+ }
+
+ /**
+ * @return TColorPickerClientSide javascript event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientSide();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TColorPickerClientSide javascript validator event options.
+ */
+ protected function createClientSide()
+ {
+ return new TColorPickerClientSide;
+ }
+
+ /**
+ * Get javascript color picker options.
+ * @return array color picker client-side options
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['ClassName'] = $this->getCssClass();
+ $options['ShowColorPicker'] = $this->getShowColorPicker();
+ if($options['ShowColorPicker'])
+ {
+ $mode = $this->getMode();
+ if($mode == TColorPickerMode::Full) $options['Mode'] = $mode;
+ else if($mode == TColorPickerMode::Simple) $options['Palette'] = 'Tiny';
+ $options['OKButtonText'] = $this->getOKButtonText();
+ $options['CancelButtonText'] = $this->getCancelButtonText();
+ }
+ $options = array_merge($options,$this->getClientSide()->getOptions()->toArray());
+ return $options;
+ }
+
+ /**
+ * @param string asset file in the self::SCRIPT_PATH directory.
+ * @return string asset file url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the color picker Css asset files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->publishColorPickerAssets();
+ }
+
+ /**
+ * Publish the color picker assets.
+ */
+ protected function publishColorPickerAssets()
+ {
+ $cs = $this->getPage()->getClientScript();
+ $key = "prado:".get_class($this);
+ $imgs['button.gif'] = $this->getAssetUrl('button.gif');
+ $imgs['background.png'] = $this->getAssetUrl('background.png');
+ $options = TJavaScript::encode($imgs);
+ $code = "Prado.WebUI.TColorPicker.UIImages = {$options};";
+ $cs->registerEndScript($key, $code);
+ $cs->registerPradoScript("colorpicker");
+ $url = $this->getAssetUrl($this->getColorPickerStyle().'.css');
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ }
+
+ /**
+ * Renders additional body content.
+ * This method overrides parent implementation by adding
+ * additional color picker button.
+ * @param THtmlWriter writer
+ */
+ public function renderEndTag($writer)
+ {
+ parent::renderEndTag($writer);
+
+ $color = $this->getText();
+ $writer->addAttribute('class', 'TColorPicker_button');
+ $writer->renderBeginTag('span');
+
+ $writer->addAttribute('id', $this->getClientID().'_button');
+ $writer->addAttribute('src', $this->getAssetUrl('button.gif'));
+ if($color !== '')
+ $writer->addAttribute('style', "background-color:{$color};");
+ $writer->addAttribute('width', '20');
+ $writer->addAttribute('height', '20');
+ $writer->addAttribute('alt', '');
+ $writer->renderBeginTag('img');
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TColorPicker';
+ }
+}
+
+/**
+ * TColorPickerMode class.
+ * TColorPickerMode defines the enumerable type for the possible UI mode
+ * that a {@link TColorPicker} control can take.
+ *
+ * The following enumerable values are defined:
+ * # Simple - Grid with 12 simple colors.
+ * # Basic - Grid with the most common 70 colors. This is the default mode.
+ * # Full - Full-featured color picker.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TColorPickerMode extends TEnumerable
+{
+ const Simple='Simple';
+ const Basic='Basic';
+ const Full='Full';
+}
+
+/**
+ * TColorPickerClientSide class.
+ *
+ * Client-side javascript code options.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TColorPickerClientSide extends TClientSideOptions
+{
+ /**
+ * @return string javascript code for when a color is selected.
+ */
+ public function getOnColorSelected()
+ {
+ return $this->getOption('OnColorSelected');
+ }
+
+ /**
+ * @param string javascript code for when a color is selected.
+ */
+ public function setOnColorSelected($javascript)
+ {
+ $this->setFunction('OnColorSelected', $javascript);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCompareValidator.php b/framework/Web/UI/WebControls/TCompareValidator.php
index 57b42018..c936f140 100644
--- a/framework/Web/UI/WebControls/TCompareValidator.php
+++ b/framework/Web/UI/WebControls/TCompareValidator.php
@@ -1,265 +1,265 @@
-<?php
-/**
- * TCompareValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TCompareValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TCompareValidator class
- *
- * TCompareValidator compares the value entered by the user into an input
- * control with the value entered into another input control or a constant value.
- * To compare the associated input control with another input control,
- * set the {@link setControlToCompare ControlToCompare} property to the ID path
- * of the control to compare with. To compare the associated input control with
- * a constant value, specify the constant value to compare with by setting the
- * {@link setValueToCompare ValueToCompare} property.
- *
- * The {@link setDataType DataType} property is used to specify the data type
- * of both comparison values. Both values are automatically converted to this data
- * type before the comparison operation is performed. The following value types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type. The format can be specified by the
- * {@link setDateFormat DateFormat} property
- * - <b>String</b> A string data type.
- *
- * Use the {@link setOperator Operator} property to specify the type of comparison
- * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
- * LessThan and LessThanEqual.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCompareValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCompareValidator';
- }
-
- /**
- * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType',TValidationDataType::String);
- }
-
- /**
- * Sets the data type that the values being
- * compared are converted to before the comparison is made.
- * @param TValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
- }
-
- /**
- * @return string the input component to compare with the input control being validated.
- */
- public function getControlToCompare()
- {
- return $this->getViewState('ControlToCompare','');
- }
-
- /**
- * Sets the input component to compare with the input control being validated.
- * @param string the ID path of the component to compare with
- */
- public function setControlToCompare($value)
- {
- $this->setViewState('ControlToCompare',$value,'');
- }
-
- /**
- * @return string the constant value to compare with the value entered by the user into the input component being validated.
- */
- public function getValueToCompare()
- {
- return $this->getViewState('ValueToCompare','');
- }
-
- /**
- * Sets the constant value to compare with the value entered by the user into the input component being validated.
- * @param string the constant value
- */
- public function setValueToCompare($value)
- {
- $this->setViewState('ValueToCompare',$value,'');
- }
-
- /**
- * @return TValidationCompareOperator the comparison operation to perform. Defaults to TValidationCompareOperator::Equal.
- */
- public function getOperator()
- {
- return $this->getViewState('Operator',TValidationCompareOperator::Equal);
- }
-
- /**
- * Sets the comparison operation to perform
- * @param TValidationCompareOperator the comparison operation
- */
- public function setOperator($value)
- {
- $this->setViewState('Operator',TPropertyValue::ensureEnum($value,'TValidationCompareOperator'),TValidationCompareOperator::Equal);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data compares successfully.
- * The validation always succeeds if ControlToValidate is not specified
- * or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
-
- if(($controlToCompare=$this->getControlToCompare())!=='')
- {
- if(($control2=$this->findControl($controlToCompare))===null)
- throw new TInvalidDataValueException('comparevalidator_controltocompare_invalid');
- if(($value2=$this->getValidationValue($control2))==='')
- return false;
- }
- else
- $value2=$this->getValueToCompare();
-
- $values = $this->getComparisonValues($value, $value2);
- switch($this->getOperator())
- {
- case TValidationCompareOperator::Equal:
- return $values[0] == $values[1];
- case TValidationCompareOperator::NotEqual:
- return $values[0] != $values[1];
- case TValidationCompareOperator::GreaterThan:
- return $values[0] > $values[1];
- case TValidationCompareOperator::GreaterThanEqual:
- return $values[0] >= $values[1];
- case TValidationCompareOperator::LessThan:
- return $values[0] < $values[1];
- case TValidationCompareOperator::LessThanEqual:
- return $values[0] <= $values[1];
- }
-
- return false;
- }
-
- /**
- * Parse the pair of values into the appropriate value type.
- * @param string value one
- * @param string second value
- * @return array appropriate type of the value pair, array($value1, $value2);
- */
- protected function getComparisonValues($value1, $value2)
- {
- switch($this->getDataType())
- {
- case TValidationDataType::Integer:
- return array(intval($value1), intval($value2));
- case TValidationDataType::Float:
- return array(floatval($value1), floatval($value2));
- case TValidationDataType::Date:
- $dateFormat = $this->getDateFormat();
- if($dateFormat!=='')
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
- return array($formatter->parse($value1), $formatter->parse($value2));
- }
- else
- return array(strtotime($value1), strtotime($value2));
- }
- return array($value1, $value2);
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- if(($name=$this->getControlToCompare())!=='')
- {
- if(($control=$this->findControl($name))!==null)
- $options['ControlToCompare']=$control->getClientID();
- }
- if(($value=$this->getValueToCompare())!=='')
- $options['ValueToCompare']=$value;
- if(($operator=$this->getOperator())!==TValidationCompareOperator::Equal)
- $options['Operator']=$operator;
- $options['DataType']=$this->getDataType();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-}
-
-
-/**
- * TValidationCompareOperator class.
- * TValidationCompareOperator defines the enumerable type for the comparison operations
- * that {@link TCompareValidator} can perform validation with.
- *
- * The following enumerable values are defined:
- * - Equal
- * - NotEqual
- * - GreaterThan
- * - GreaterThanEqual
- * - LessThan
- * - LessThanEqual
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationCompareOperator extends TEnumerable
-{
- const Equal='Equal';
- const NotEqual='NotEqual';
- const GreaterThan='GreaterThan';
- const GreaterThanEqual='GreaterThanEqual';
- const LessThan='LessThan';
- const LessThanEqual='LessThanEqual';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TCompareValidator class
+ *
+ * TCompareValidator compares the value entered by the user into an input
+ * control with the value entered into another input control or a constant value.
+ * To compare the associated input control with another input control,
+ * set the {@link setControlToCompare ControlToCompare} property to the ID path
+ * of the control to compare with. To compare the associated input control with
+ * a constant value, specify the constant value to compare with by setting the
+ * {@link setValueToCompare ValueToCompare} property.
+ *
+ * The {@link setDataType DataType} property is used to specify the data type
+ * of both comparison values. Both values are automatically converted to this data
+ * type before the comparison operation is performed. The following value types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type. The format can be specified by the
+ * {@link setDateFormat DateFormat} property
+ * - <b>String</b> A string data type.
+ *
+ * Use the {@link setOperator Operator} property to specify the type of comparison
+ * to perform. Valid operators include Equal, NotEqual, GreaterThan, GreaterThanEqual,
+ * LessThan and LessThanEqual.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCompareValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCompareValidator';
+ }
+
+ /**
+ * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType',TValidationDataType::String);
+ }
+
+ /**
+ * Sets the data type that the values being
+ * compared are converted to before the comparison is made.
+ * @param TValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
+ }
+
+ /**
+ * @return string the input component to compare with the input control being validated.
+ */
+ public function getControlToCompare()
+ {
+ return $this->getViewState('ControlToCompare','');
+ }
+
+ /**
+ * Sets the input component to compare with the input control being validated.
+ * @param string the ID path of the component to compare with
+ */
+ public function setControlToCompare($value)
+ {
+ $this->setViewState('ControlToCompare',$value,'');
+ }
+
+ /**
+ * @return string the constant value to compare with the value entered by the user into the input component being validated.
+ */
+ public function getValueToCompare()
+ {
+ return $this->getViewState('ValueToCompare','');
+ }
+
+ /**
+ * Sets the constant value to compare with the value entered by the user into the input component being validated.
+ * @param string the constant value
+ */
+ public function setValueToCompare($value)
+ {
+ $this->setViewState('ValueToCompare',$value,'');
+ }
+
+ /**
+ * @return TValidationCompareOperator the comparison operation to perform. Defaults to TValidationCompareOperator::Equal.
+ */
+ public function getOperator()
+ {
+ return $this->getViewState('Operator',TValidationCompareOperator::Equal);
+ }
+
+ /**
+ * Sets the comparison operation to perform
+ * @param TValidationCompareOperator the comparison operation
+ */
+ public function setOperator($value)
+ {
+ $this->setViewState('Operator',TPropertyValue::ensureEnum($value,'TValidationCompareOperator'),TValidationCompareOperator::Equal);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data compares successfully.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+
+ if(($controlToCompare=$this->getControlToCompare())!=='')
+ {
+ if(($control2=$this->findControl($controlToCompare))===null)
+ throw new TInvalidDataValueException('comparevalidator_controltocompare_invalid');
+ if(($value2=$this->getValidationValue($control2))==='')
+ return false;
+ }
+ else
+ $value2=$this->getValueToCompare();
+
+ $values = $this->getComparisonValues($value, $value2);
+ switch($this->getOperator())
+ {
+ case TValidationCompareOperator::Equal:
+ return $values[0] == $values[1];
+ case TValidationCompareOperator::NotEqual:
+ return $values[0] != $values[1];
+ case TValidationCompareOperator::GreaterThan:
+ return $values[0] > $values[1];
+ case TValidationCompareOperator::GreaterThanEqual:
+ return $values[0] >= $values[1];
+ case TValidationCompareOperator::LessThan:
+ return $values[0] < $values[1];
+ case TValidationCompareOperator::LessThanEqual:
+ return $values[0] <= $values[1];
+ }
+
+ return false;
+ }
+
+ /**
+ * Parse the pair of values into the appropriate value type.
+ * @param string value one
+ * @param string second value
+ * @return array appropriate type of the value pair, array($value1, $value2);
+ */
+ protected function getComparisonValues($value1, $value2)
+ {
+ switch($this->getDataType())
+ {
+ case TValidationDataType::Integer:
+ return array(intval($value1), intval($value2));
+ case TValidationDataType::Float:
+ return array(floatval($value1), floatval($value2));
+ case TValidationDataType::Date:
+ $dateFormat = $this->getDateFormat();
+ if($dateFormat!=='')
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
+ return array($formatter->parse($value1), $formatter->parse($value2));
+ }
+ else
+ return array(strtotime($value1), strtotime($value2));
+ }
+ return array($value1, $value2);
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ if(($name=$this->getControlToCompare())!=='')
+ {
+ if(($control=$this->findControl($name))!==null)
+ $options['ControlToCompare']=$control->getClientID();
+ }
+ if(($value=$this->getValueToCompare())!=='')
+ $options['ValueToCompare']=$value;
+ if(($operator=$this->getOperator())!==TValidationCompareOperator::Equal)
+ $options['Operator']=$operator;
+ $options['DataType']=$this->getDataType();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+}
+
+
+/**
+ * TValidationCompareOperator class.
+ * TValidationCompareOperator defines the enumerable type for the comparison operations
+ * that {@link TCompareValidator} can perform validation with.
+ *
+ * The following enumerable values are defined:
+ * - Equal
+ * - NotEqual
+ * - GreaterThan
+ * - GreaterThanEqual
+ * - LessThan
+ * - LessThanEqual
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationCompareOperator extends TEnumerable
+{
+ const Equal='Equal';
+ const NotEqual='NotEqual';
+ const GreaterThan='GreaterThan';
+ const GreaterThanEqual='GreaterThanEqual';
+ const LessThan='LessThan';
+ const LessThanEqual='LessThanEqual';
+}
+
diff --git a/framework/Web/UI/WebControls/TConditional.php b/framework/Web/UI/WebControls/TConditional.php
index d04324f0..28af2305 100644
--- a/framework/Web/UI/WebControls/TConditional.php
+++ b/framework/Web/UI/WebControls/TConditional.php
@@ -1,143 +1,143 @@
-<?php
-/**
- * TConditional class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TConditional class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TConditional class.
- *
- * TConditional displays appropriate content based on the evaluation result
- * of a PHP expression specified via {@link setCondition Condition}.
- * If the result is true, it instantiates the template {@link getTrueTemplate TrueTemplate};
- * otherwise, the template {@link getFalseTemplate FalseTemplate} is instantiated.
- * The PHP expression is evaluated right before {@link onInit} stage of the control lifecycle.
- *
- * Since {@link setCondition Condition} is evaluated at a very early stage, it is recommended
- * you set {@link setCondition Condition} in template and the expression should not refer to
- * objects that are available on or after {@link onInit} lifecycle.
- *
- * A typical usage of TConditional is shown as following:
- * <code>
- * <com:TConditional Condition="$this->User->IsGuest">
- * <prop:TrueTemplate>
- * <a href="path/to/login">Login</a>
- * </prop:TrueTemplate>
- * <prop:FalseTemplate>
- * <a href="path/to/logout">Logout</a>
- * </prop:FalseTemplate>
- * </com:TConditional>
- * </code>
- *
- * TConditional is very light. It instantiates either {@link getTrueTemplate TrueTemplate}
- * or {@link getFalseTemplate FalseTemplate}, but never both. And the condition is evaluated only once.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TConditional extends TControl
-{
- private $_condition='true';
- private $_trueTemplate;
- private $_falseTemplate;
- private $_creatingChildren=false;
-
- /**
- * Processes an object that is created during parsing template.
- * This method overrides the parent implementation by removing
- * all contents enclosed in the template tag.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- if($this->_creatingChildren)
- parent::addParsedObject($object);
- }
-
- /**
- * Creates child controls.
- * This method overrides the parent implementation. It evaluates {@link getCondition Condition}
- * and instantiate the corresponding template.
- */
- public function createChildControls()
- {
- $this->_creatingChildren=true;
- $result=true;
- try
- {
- $result=$this->getTemplateControl()->evaluateExpression($this->_condition);
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('conditional_condition_invalid',$this->_condition,$e->getMessage());
- }
- if($result)
- {
- if($this->_trueTemplate)
- $this->_trueTemplate->instantiateIn($this->getTemplateControl(),$this);
- }
- else if($this->_falseTemplate)
- $this->_falseTemplate->instantiateIn($this->getTemplateControl(),$this);
- $this->_creatingChildren=false;
- }
-
- /**
- * @return string the PHP expression used for determining which template to use. Defaults to 'true', meaning using TrueTemplate.
- */
- public function getCondition()
- {
- return $this->_condition;
- }
-
- /**
- * Sets the PHP expression to be evaluated for conditionally displaying content.
- * The context of the expression is the template control containing TConditional.
- * @param string the PHP expression used for determining which template to use.
- */
- public function setCondition($value)
- {
- $this->_condition=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return ITemplate the template applied when {@link getCondition Condition} is true.
- */
- public function getTrueTemplate()
- {
- return $this->_trueTemplate;
- }
-
- /**
- * @param ITemplate the template applied when {@link getCondition Condition} is true.
- */
- public function setTrueTemplate(ITemplate $value)
- {
- $this->_trueTemplate=$value;
- }
-
- /**
- * @return ITemplate the template applied when {@link getCondition Condition} is false.
- */
- public function getFalseTemplate()
- {
- return $this->_falseTemplate;
- }
-
- /**
- * @param ITemplate the template applied when {@link getCondition Condition} is false.
- */
- public function setFalseTemplate(ITemplate $value)
- {
- $this->_falseTemplate=$value;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TConditional class.
+ *
+ * TConditional displays appropriate content based on the evaluation result
+ * of a PHP expression specified via {@link setCondition Condition}.
+ * If the result is true, it instantiates the template {@link getTrueTemplate TrueTemplate};
+ * otherwise, the template {@link getFalseTemplate FalseTemplate} is instantiated.
+ * The PHP expression is evaluated right before {@link onInit} stage of the control lifecycle.
+ *
+ * Since {@link setCondition Condition} is evaluated at a very early stage, it is recommended
+ * you set {@link setCondition Condition} in template and the expression should not refer to
+ * objects that are available on or after {@link onInit} lifecycle.
+ *
+ * A typical usage of TConditional is shown as following:
+ * <code>
+ * <com:TConditional Condition="$this->User->IsGuest">
+ * <prop:TrueTemplate>
+ * <a href="path/to/login">Login</a>
+ * </prop:TrueTemplate>
+ * <prop:FalseTemplate>
+ * <a href="path/to/logout">Logout</a>
+ * </prop:FalseTemplate>
+ * </com:TConditional>
+ * </code>
+ *
+ * TConditional is very light. It instantiates either {@link getTrueTemplate TrueTemplate}
+ * or {@link getFalseTemplate FalseTemplate}, but never both. And the condition is evaluated only once.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TConditional extends TControl
+{
+ private $_condition='true';
+ private $_trueTemplate;
+ private $_falseTemplate;
+ private $_creatingChildren=false;
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method overrides the parent implementation by removing
+ * all contents enclosed in the template tag.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ if($this->_creatingChildren)
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * Creates child controls.
+ * This method overrides the parent implementation. It evaluates {@link getCondition Condition}
+ * and instantiate the corresponding template.
+ */
+ public function createChildControls()
+ {
+ $this->_creatingChildren=true;
+ $result=true;
+ try
+ {
+ $result=$this->getTemplateControl()->evaluateExpression($this->_condition);
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('conditional_condition_invalid',$this->_condition,$e->getMessage());
+ }
+ if($result)
+ {
+ if($this->_trueTemplate)
+ $this->_trueTemplate->instantiateIn($this->getTemplateControl(),$this);
+ }
+ else if($this->_falseTemplate)
+ $this->_falseTemplate->instantiateIn($this->getTemplateControl(),$this);
+ $this->_creatingChildren=false;
+ }
+
+ /**
+ * @return string the PHP expression used for determining which template to use. Defaults to 'true', meaning using TrueTemplate.
+ */
+ public function getCondition()
+ {
+ return $this->_condition;
+ }
+
+ /**
+ * Sets the PHP expression to be evaluated for conditionally displaying content.
+ * The context of the expression is the template control containing TConditional.
+ * @param string the PHP expression used for determining which template to use.
+ */
+ public function setCondition($value)
+ {
+ $this->_condition=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return ITemplate the template applied when {@link getCondition Condition} is true.
+ */
+ public function getTrueTemplate()
+ {
+ return $this->_trueTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when {@link getCondition Condition} is true.
+ */
+ public function setTrueTemplate(ITemplate $value)
+ {
+ $this->_trueTemplate=$value;
+ }
+
+ /**
+ * @return ITemplate the template applied when {@link getCondition Condition} is false.
+ */
+ public function getFalseTemplate()
+ {
+ return $this->_falseTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when {@link getCondition Condition} is false.
+ */
+ public function setFalseTemplate(ITemplate $value)
+ {
+ $this->_falseTemplate=$value;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TContent.php b/framework/Web/UI/WebControls/TContent.php
index 3b17c2cc..60a8e0b6 100644
--- a/framework/Web/UI/WebControls/TContent.php
+++ b/framework/Web/UI/WebControls/TContent.php
@@ -1,47 +1,47 @@
-<?php
-/**
- * TContent class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TContent class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TContent class
- *
- * TContent specifies a block of content on a control's template
- * that will be injected at somewhere of the master control's template.
- * TContentPlaceHolder and {@link TContent} together implement a decoration
- * pattern for prado templated controls. A template control
- * (called content control) can specify a master control
- * whose template contains some TContentPlaceHolder controls.
- * {@link TContent} controls on the content control's template will replace the corresponding
- * {@link TContentPlaceHolder} controls on the master control's template.
- * This is called content injection. It is done by matching the IDs of
- * {@link TContent} and {@link TContentPlaceHolder} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TContent extends TControl implements INamingContainer
-{
- /**
- * This method is invoked after the control is instantiated on a template.
- * This overrides the parent implementation by registering the content control
- * to the template owner control.
- * @param TControl potential parent of this control
- */
- public function createdOnTemplate($parent)
- {
- if(($id=$this->getID())==='')
- throw new TConfigurationException('content_id_required');
- $this->getTemplateControl()->registerContent($id,$this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TContent class
+ *
+ * TContent specifies a block of content on a control's template
+ * that will be injected at somewhere of the master control's template.
+ * TContentPlaceHolder and {@link TContent} together implement a decoration
+ * pattern for prado templated controls. A template control
+ * (called content control) can specify a master control
+ * whose template contains some TContentPlaceHolder controls.
+ * {@link TContent} controls on the content control's template will replace the corresponding
+ * {@link TContentPlaceHolder} controls on the master control's template.
+ * This is called content injection. It is done by matching the IDs of
+ * {@link TContent} and {@link TContentPlaceHolder} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TContent extends TControl implements INamingContainer
+{
+ /**
+ * This method is invoked after the control is instantiated on a template.
+ * This overrides the parent implementation by registering the content control
+ * to the template owner control.
+ * @param TControl potential parent of this control
+ */
+ public function createdOnTemplate($parent)
+ {
+ if(($id=$this->getID())==='')
+ throw new TConfigurationException('content_id_required');
+ $this->getTemplateControl()->registerContent($id,$this);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TContentPlaceHolder.php b/framework/Web/UI/WebControls/TContentPlaceHolder.php
index ddd2b610..55ed461d 100644
--- a/framework/Web/UI/WebControls/TContentPlaceHolder.php
+++ b/framework/Web/UI/WebControls/TContentPlaceHolder.php
@@ -1,48 +1,48 @@
-<?php
-/**
- * TContentPlaceHolder class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TContentPlaceHolder class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TContentPlaceHolder class
- *
- * TContentPlaceHolder reserves a place on a template where a {@link TContent}
- * control can inject itself and its children in. TContentPlaceHolder and {@link TContent}
- * together implement a decoration pattern for prado templated controls.
- * A template control (called content control) can specify a master control
- * whose template contains some TContentPlaceHolder controls.
- * {@link TContent} controls on the content control's template will replace the corresponding
- * {@link TContentPlaceHolder} controls on the master control's template.
- * This is called content injection. It is done by matching the IDs of
- * {@link TContent} and {@link TContentPlaceHolder} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TContentPlaceHolder extends TControl
-{
- /**
- * This method is invoked after the control is instantiated on a template.
- * This overrides the parent implementation by registering the content placeholder
- * control to the template owner control. The placeholder control will NOT
- * be added to the potential parent control!
- * @param TControl potential parent of this control
- */
- public function createdOnTemplate($parent)
- {
- if(($id=$this->getID())==='')
- throw new TConfigurationException('contentplaceholder_id_required');
- $this->getTemplateControl()->registerContentPlaceHolder($id,$this);
- $parent->getControls()->add($this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TContentPlaceHolder class
+ *
+ * TContentPlaceHolder reserves a place on a template where a {@link TContent}
+ * control can inject itself and its children in. TContentPlaceHolder and {@link TContent}
+ * together implement a decoration pattern for prado templated controls.
+ * A template control (called content control) can specify a master control
+ * whose template contains some TContentPlaceHolder controls.
+ * {@link TContent} controls on the content control's template will replace the corresponding
+ * {@link TContentPlaceHolder} controls on the master control's template.
+ * This is called content injection. It is done by matching the IDs of
+ * {@link TContent} and {@link TContentPlaceHolder} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TContentPlaceHolder extends TControl
+{
+ /**
+ * This method is invoked after the control is instantiated on a template.
+ * This overrides the parent implementation by registering the content placeholder
+ * control to the template owner control. The placeholder control will NOT
+ * be added to the potential parent control!
+ * @param TControl potential parent of this control
+ */
+ public function createdOnTemplate($parent)
+ {
+ if(($id=$this->getID())==='')
+ throw new TConfigurationException('contentplaceholder_id_required');
+ $this->getTemplateControl()->registerContentPlaceHolder($id,$this);
+ $parent->getControls()->add($this);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TCustomValidator.php b/framework/Web/UI/WebControls/TCustomValidator.php
index 9ab75258..dcfadacd 100644
--- a/framework/Web/UI/WebControls/TCustomValidator.php
+++ b/framework/Web/UI/WebControls/TCustomValidator.php
@@ -1,207 +1,207 @@
-<?php
-/**
- * TCustomValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TCustomValidator class
- *
- * TCustomValidator performs user-defined validation (either
- * server-side or client-side or both) on an input component.
- *
- * To create a server-side validation function, provide a handler for
- * the {@link onServerValidate OnServerValidate} event that performs the validation.
- * The data string of the input control to validate can be accessed
- * by {@link TServerValidateEventParameter::getValue Value} of the event parameter.
- * The result of the validation should be stored in the
- * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event
- * parameter.
- *
- * To create a client-side validation function, add the client-side
- * validation javascript function to the page template.
- * The function should have the following signature:
- * <code>
- * <script type="text/javascript"><!--
- * function ValidationFunctionName(sender, parameter)
- * {
- * // if(parameter == ...)
- * // return true;
- * // else
- * // return false;
- * }
- * --></script>
- * </code>
- * Use the {@link setClientValidationFunction ClientValidationFunction} property
- * to specify the name of the client-side validation script function associated
- * with the TCustomValidator.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCustomValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TCustomValidator';
- }
-
- /**
- * @return string the name of the custom client-side script function used for validation.
- */
- public function getClientValidationFunction()
- {
- return $this->getViewState('ClientValidationFunction','');
- }
-
- /**
- * Sets the name of the custom client-side script function used for validation.
- * @param string the script function name
- */
- public function setClientValidationFunction($value)
- {
- $this->setViewState('ClientValidationFunction',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if {@link onServerValidate} returns true.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- $value = '';
- if($this->getValidationTarget()!==null)
- $value=$this->getValidationValue($this->getValidationTarget());
- return $this->onServerValidate($value);
- }
-
- /**
- * This method is invoked when the server side validation happens.
- * It will raise the <b>OnServerValidate</b> event.
- * The method also allows derived classes to handle the event without attaching a delegate.
- * <b>Note</b> The derived classes should call parent implementation
- * to ensure the <b>OnServerValidate</b> event is raised.
- * @param string the value to be validated
- * @return boolean whether the value is valid
- */
- public function onServerValidate($value)
- {
- $param=new TServerValidateEventParameter($value,true);
- $this->raiseEvent('OnServerValidate',$this,$param);
- return $param->getIsValid();
- }
-
- /**
- * @return TControl control to be validated. Null if no control is found.
- */
- public function getValidationTarget()
- {
- if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
- return $control;
- else if(($id=$this->getControlToValidate())!=='')
- throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
- else
- return null;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- if(($clientJs=$this->getClientValidationFunction())!=='')
- $options['ClientValidationFunction']=$clientJs;
- return $options;
- }
-
- /**
- * Only register the client-side validator if
- * {@link setClientValidationFunction ClientValidationFunction} is set.
- */
- protected function registerClientScriptValidator()
- {
- if($this->getClientValidationFunction()!=='')
- parent::registerClientScriptValidator();
- }
-}
-
-/**
- * TServerValidateEventParameter class
- *
- * TServerValidateEventParameter encapsulates the parameter data for
- * <b>OnServerValidate</b> event of TCustomValidator components.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TServerValidateEventParameter extends TEventParameter
-{
- /**
- * the value to be validated
- * @var string
- */
- private $_value='';
- /**
- * whether the value is valid
- * @var boolean
- */
- private $_isValid=true;
-
- /**
- * Constructor.
- * @param string property value to be validated
- * @param boolean whether the value is valid
- */
- public function __construct($value,$isValid)
- {
- $this->_value=$value;
- $this->setIsValid($isValid);
- }
-
- /**
- * @return string value to be validated
- */
- public function getValue()
- {
- return $this->_value;
- }
-
- /**
- * @return boolean whether the value is valid
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the value is valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+<?php
+/**
+ * TCustomValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TCustomValidator class
+ *
+ * TCustomValidator performs user-defined validation (either
+ * server-side or client-side or both) on an input component.
+ *
+ * To create a server-side validation function, provide a handler for
+ * the {@link onServerValidate OnServerValidate} event that performs the validation.
+ * The data string of the input control to validate can be accessed
+ * by {@link TServerValidateEventParameter::getValue Value} of the event parameter.
+ * The result of the validation should be stored in the
+ * {@link TServerValidateEventParameter::getIsValid IsValid} property of the event
+ * parameter.
+ *
+ * To create a client-side validation function, add the client-side
+ * validation javascript function to the page template.
+ * The function should have the following signature:
+ * <code>
+ * <script type="text/javascript"><!--
+ * function ValidationFunctionName(sender, parameter)
+ * {
+ * // if(parameter == ...)
+ * // return true;
+ * // else
+ * // return false;
+ * }
+ * --></script>
+ * </code>
+ * Use the {@link setClientValidationFunction ClientValidationFunction} property
+ * to specify the name of the client-side validation script function associated
+ * with the TCustomValidator.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCustomValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TCustomValidator';
+ }
+
+ /**
+ * @return string the name of the custom client-side script function used for validation.
+ */
+ public function getClientValidationFunction()
+ {
+ return $this->getViewState('ClientValidationFunction','');
+ }
+
+ /**
+ * Sets the name of the custom client-side script function used for validation.
+ * @param string the script function name
+ */
+ public function setClientValidationFunction($value)
+ {
+ $this->setViewState('ClientValidationFunction',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if {@link onServerValidate} returns true.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ $value = '';
+ if($this->getValidationTarget()!==null)
+ $value=$this->getValidationValue($this->getValidationTarget());
+ return $this->onServerValidate($value);
+ }
+
+ /**
+ * This method is invoked when the server side validation happens.
+ * It will raise the <b>OnServerValidate</b> event.
+ * The method also allows derived classes to handle the event without attaching a delegate.
+ * <b>Note</b> The derived classes should call parent implementation
+ * to ensure the <b>OnServerValidate</b> event is raised.
+ * @param string the value to be validated
+ * @return boolean whether the value is valid
+ */
+ public function onServerValidate($value)
+ {
+ $param=new TServerValidateEventParameter($value,true);
+ $this->raiseEvent('OnServerValidate',$this,$param);
+ return $param->getIsValid();
+ }
+
+ /**
+ * @return TControl control to be validated. Null if no control is found.
+ */
+ public function getValidationTarget()
+ {
+ if(($id=$this->getControlToValidate())!=='' && ($control=$this->findControl($id))!==null)
+ return $control;
+ else if(($id=$this->getControlToValidate())!=='')
+ throw new TInvalidDataTypeException('basevalidator_validatable_required',get_class($this));
+ else
+ return null;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ if(($clientJs=$this->getClientValidationFunction())!=='')
+ $options['ClientValidationFunction']=$clientJs;
+ return $options;
+ }
+
+ /**
+ * Only register the client-side validator if
+ * {@link setClientValidationFunction ClientValidationFunction} is set.
+ */
+ protected function registerClientScriptValidator()
+ {
+ if($this->getClientValidationFunction()!=='')
+ parent::registerClientScriptValidator();
+ }
+}
+
+/**
+ * TServerValidateEventParameter class
+ *
+ * TServerValidateEventParameter encapsulates the parameter data for
+ * <b>OnServerValidate</b> event of TCustomValidator components.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TServerValidateEventParameter extends TEventParameter
+{
+ /**
+ * the value to be validated
+ * @var string
+ */
+ private $_value='';
+ /**
+ * whether the value is valid
+ * @var boolean
+ */
+ private $_isValid=true;
+
+ /**
+ * Constructor.
+ * @param string property value to be validated
+ * @param boolean whether the value is valid
+ */
+ public function __construct($value,$isValid)
+ {
+ $this->_value=$value;
+ $this->setIsValid($isValid);
+ }
+
+ /**
+ * @return string value to be validated
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+
+ /**
+ * @return boolean whether the value is valid
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the value is valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php
index 294dd416..076179fb 100644
--- a/framework/Web/UI/WebControls/TDataBoundControl.php
+++ b/framework/Web/UI/WebControls/TDataBoundControl.php
@@ -1,587 +1,587 @@
-<?php
-/**
- * TDataBoundControl class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataSourceControl');
-Prado::using('System.Web.UI.WebControls.TDataSourceView');
-Prado::using('System.Collections.TPagedDataSource');
-
-/**
- * TDataBoundControl class.
- *
- * TDataBoundControl is the based class for controls that need to populate
- * data from data sources. It provides basic properties and methods that allow
- * the derived controls to associate with data sources and retrieve data from them.
- *
- * TBC....
- *
- * TDataBoundControl is equipped with paging capabilities. By setting
- * {@link setAllowPaging AllowPaging} to true, the input data will be paged
- * and only one page of data is actually populated into the data-bound control.
- * This saves a lot of memory when dealing with larget datasets.
- *
- * To specify the number of data items displayed on each page, set
- * the {@link setPageSize PageSize} property, and to specify which
- * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
- *
- * When the size of the original data is too big to be loaded all in the memory,
- * one can enable custom paging. In custom paging, the total number of data items
- * is specified manually via {@link setVirtualItemCount VirtualItemCount},
- * and the data source only needs to contain the current page of data. To enable
- * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataBoundControl extends TWebControl
-{
- private $_initialized=false;
- private $_dataSource=null;
- private $_requiresBindToNull=false;
- private $_requiresDataBinding=false;
- private $_prerendered=false;
- private $_currentView=null;
- private $_currentDataSource=null;
- private $_currentViewValid=false;
- private $_currentDataSourceValid=false;
- private $_currentViewIsFromDataSourceID=false;
- private $_parameters=null;
- private $_isDataBound=false;
-
- /**
- * @return Traversable data source object, defaults to null.
- */
- public function getDataSource()
- {
- return $this->_dataSource;
- }
-
- /**
- * Sets the data source object associated with the databound control.
- * The data source must implement Traversable interface.
- * If an array is given, it will be converted to xxx.
- * If a string is given, it will be converted to xxx.
- * @param Traversable|array|string data source object
- */
- public function setDataSource($value)
- {
- $this->_dataSource=$this->validateDataSource($value);
- $this->onDataSourceChanged();
- }
-
- /**
- * @return string ID path to the data source control. Defaults to empty.
- */
- public function getDataSourceID()
- {
- return $this->getViewState('DataSourceID','');
- }
-
- /**
- * @param string ID path to the data source control. The data source
- * control must be locatable via {@link TControl::findControl} call.
- */
- public function setDataSourceID($value)
- {
- $dsid=$this->getViewState('DataSourceID','');
- if($dsid!=='' && $value==='')
- $this->_requiresBindToNull=true;
- $this->setViewState('DataSourceID',$value,'');
- $this->onDataSourceChanged();
- }
-
- /**
- * @return boolean if the databound control uses the data source specified
- * by {@link setDataSourceID}, or it uses the data source object specified
- * by {@link setDataSource}.
- */
- protected function getUsingDataSourceID()
- {
- return $this->getDataSourceID()!=='';
- }
-
- /**
- * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
- * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
- */
- public function onDataSourceChanged()
- {
- $this->_currentViewValid=false;
- $this->_currentDataSourceValid=false;
- if($this->getInitialized())
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * @return boolean whether the databound control has been initialized.
- * By default, the control is initialized after its viewstate has been restored.
- */
- protected function getInitialized()
- {
- return $this->_initialized;
- }
-
- /**
- * Sets a value indicating whether the databound control is initialized.
- * If initialized, any modification to {@link setDataSource DataSource} or
- * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
- * as true.
- * @param boolean a value indicating whether the databound control is initialized.
- */
- protected function setInitialized($value)
- {
- $this->_initialized=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether databind has been invoked in the previous page request
- */
- protected function getIsDataBound()
- {
- return $this->_isDataBound;
- }
-
- /**
- * @param boolean if databind has been invoked in this page request
- */
- protected function setIsDataBound($value)
- {
- $this->_isDataBound=$value;
- }
-
- /**
- * @return boolean whether a databind call is required (by the data bound control)
- */
- protected function getRequiresDataBinding()
- {
- return $this->_requiresDataBinding;
- }
-
- /**
- * @return boolean whether paging is enabled. Defaults to false.
- */
- public function getAllowPaging()
- {
- return $this->getViewState('AllowPaging',false);
- }
-
- /**
- * @param boolean whether paging is enabled
- */
- public function setAllowPaging($value)
- {
- $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the custom paging is enabled. Defaults to false.
- */
- public function getAllowCustomPaging()
- {
- return $this->getViewState('AllowCustomPaging',false);
- }
-
- /**
- * Sets a value indicating whether the custom paging should be enabled.
- * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
- * property is used to determine the paging, and the data items in the
- * {@link setDataSource DataSource} are considered to be in the current page.
- * @param boolean whether the custom paging is enabled
- */
- public function setAllowCustomPaging($value)
- {
- $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer the number of data items on each page. Defaults to 10.
- */
- public function getPageSize()
- {
- return $this->getViewState('PageSize',10);
- }
-
- /**
- * @param integer the number of data items on each page.
- * @throws TInvalidDataValueException if the value is less than 1
- */
- public function setPageSize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
- $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
- }
-
- /**
- * @return integer number of pages of data items available
- */
- public function getPageCount()
- {
- return $this->getViewState('PageCount',1);
- }
-
- /**
- * @return integer virtual number of data items in the data source. Defaults to 0.
- * @see setAllowCustomPaging
- */
- public function getVirtualItemCount()
- {
- return $this->getViewState('VirtualItemCount',0);
- }
-
- /**
- * @param integer virtual number of data items in the data source.
- * @throws TInvalidDataValueException if the value is less than 0
- * @see setAllowCustomPaging
- */
- public function setVirtualItemCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
- $this->setViewState('VirtualItemCount',$value,0);
- }
-
- /**
- * Sets a value indicating whether a databind call is required by the data bound control.
- * If true and the control has been prerendered while it uses the data source
- * specified by {@link setDataSourceID}, a databind call will be called by this method.
- * @param boolean whether a databind call is required.
- */
- protected function setRequiresDataBinding($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- if($value && $this->_prerendered)
- {
- $this->_requiresDataBinding=true;
- $this->ensureDataBound();
- }
- else
- $this->_requiresDataBinding=$value;
- }
-
- /**
- * Ensures any pending {@link dataBind} is called.
- * This method calls {@link dataBind} if the data source is specified
- * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
- * is true.
- */
- protected function ensureDataBound()
- {
- if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
- {
- $this->dataBind();
- $this->_requiresBindToNull=false;
- }
- }
-
- /**
- * @return TPagedDataSource creates a paged data source
- */
- protected function createPagedDataSource()
- {
- $ds=new TPagedDataSource;
- $ds->setCurrentPageIndex($this->getCurrentPageIndex());
- $ds->setPageSize($this->getPageSize());
- $ds->setAllowPaging($this->getAllowPaging());
- $ds->setAllowCustomPaging($this->getAllowCustomPaging());
- $ds->setVirtualItemCount($this->getVirtualItemCount());
- return $ds;
- }
-
- /**
- * Performs databinding.
- * This method overrides the parent implementation by calling
- * {@link performSelect} which fetches data from data source and does
- * the actual binding work.
- */
- public function dataBind()
- {
- $this->setRequiresDataBinding(false);
- $this->dataBindProperties();
- $this->onDataBinding(null);
-
- if(($view=$this->getDataSourceView())!==null)
- $data=$view->select($this->getSelectParameters());
- else
- $data=null;
-
- if($data instanceof Traversable)
- {
- if($this->getAllowPaging())
- {
- $ds=$this->createPagedDataSource();
- $ds->setDataSource($data);
- $this->setViewState('PageCount',$ds->getPageCount());
- if($ds->getCurrentPageIndex()>=$ds->getPageCount())
- {
- $ds->setCurrentPageIndex($ds->getPageCount()-1);
- $this->setCurrentPageIndex($ds->getCurrentPageIndex());
- }
- $this->performDataBinding($ds);
- }
- else
- {
- $this->clearViewState('PageCount');
- $this->performDataBinding($data);
- }
- }
- $this->setIsDataBound(true);
- $this->onDataBound(null);
- }
-
- public function dataSourceViewChanged($sender,$param)
- {
- if(!$this->_ignoreDataSourceViewChanged)
- $this->setRequiresDataBinding(true);
- }
-
- protected function getDataSourceView()
- {
- if(!$this->_currentViewValid)
- {
- if($this->_currentView && $this->_currentViewIsFromDataSourceID)
- $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
- if(($dataSource=$this->determineDataSource())!==null)
- {
- if(($view=$dataSource->getView($this->getDataMember()))===null)
- throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
- if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
- $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
- $this->_currentView=$view;
- }
- else
- $this->_currentView=null;
- $this->_currentViewValid=true;
- }
- return $this->_currentView;
- }
-
- protected function determineDataSource()
- {
- if(!$this->_currentDataSourceValid)
- {
- if(($dsid=$this->getDataSourceID())!=='')
- {
- if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
- else if(!($dataSource instanceof IDataSource))
- throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
- else
- $this->_currentDataSource=$dataSource;
- }
- else if(($dataSource=$this->getDataSource())!==null)
- $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
- else
- $this->_currentDataSource=null;
- $this->_currentDataSourceValid=true;
- }
- return $this->_currentDataSource;
- }
-
- abstract protected function performDataBinding($data);
-
- /**
- * Raises <b>OnDataBound</b> event.
- * This method should be invoked after a databind is performed.
- * It is mainly used by framework and component developers.
- */
- public function onDataBound($param)
- {
- $this->raiseEvent('OnDataBound',$this,$param);
- }
-
- /**
- * Sets page's <b>OnPreLoad</b> event handler as {@link pagePreLoad}.
- * If viewstate is disabled and the current request is a postback,
- * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $page=$this->getPage();
- $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
- }
-
- /**
- * Sets {@link getInitialized} as true.
- * This method is invoked when page raises <b>PreLoad</b> event.
- * @param mixed event sender
- * @param TEventParameter event parameter
- */
- public function pagePreLoad($sender,$param)
- {
- $this->_initialized=true;
- $isPostBack=$this->getPage()->getIsPostBack();
- if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
- $this->setRequiresDataBinding(true);
- }
-
- /**
- * Ensures any pending databind is performed.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onPreRender($param)
- {
- $this->_prerendered=true;
- $this->ensureDataBound();
- parent::onPreRender($param);
- }
-
- /**
- * Validates if the parameter is a valid data source.
- * If it is a string or an array, it will be converted as a TList object.
- * @param Traversable|array|string data source to be validated
- * @return Traversable the data that is traversable
- * @throws TInvalidDataTypeException if the data is neither null nor Traversable
- */
- protected function validateDataSource($value)
- {
- if(is_string($value))
- {
- $list=new TList;
- foreach(TPropertyValue::ensureArray($value) as $key=>$value)
- {
- if(is_array($value))
- $list->add($value);
- else
- $list->add(array($value,is_string($key)?$key:$value));
- }
- return $list;
- }
- else if(is_array($value))
- return new TMap($value);
- else if($value instanceof TDbDataReader) {
- // read array from TDbDataReader since it's forward-only stream and can only be traversed once
- return $value->readAll();
- }
- else if(($value instanceof Traversable) || $value===null)
- return $value;
- else
- throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
- }
-
- public function getDataMember()
- {
- return $this->getViewState('DataMember','');
- }
-
- public function setDataMember($value)
- {
- $this->setViewState('DataMember',$value,'');
- }
-
- public function getSelectParameters()
- {
- if(!$this->_parameters)
- $this->_parameters=new TDataSourceSelectParameters;
- return $this->_parameters;
- }
-}
-
-
-/**
- * TListItemType class.
- * TListItemType defines the enumerable type for the possible types
- * that databound list items could take.
- *
- * The following enumerable values are defined:
- * - Header: header item
- * - Footer: footer item
- * - Item: content item (neither header nor footer)
- * - Separator: separator between items
- * - AlternatingItem: alternating content item
- * - EditItem: content item in edit mode
- * - SelectedItem: selected content item
- * - Pager: pager
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TListItemType extends TEnumerable
-{
- const Header='Header';
- const Footer='Footer';
- const Item='Item';
- const Separator='Separator';
- const AlternatingItem='AlternatingItem';
- const EditItem='EditItem';
- const SelectedItem='SelectedItem';
- const Pager='Pager';
-}
-
-
-/**
- * IItemDataRenderer interface.
- *
- * IItemDataRenderer defines the interface that an item renderer
- * needs to implement. Besides the {@link getData Data} property, a list item
- * renderer also needs to provide {@link getItemIndex ItemIndex} and
- * {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-interface IItemDataRenderer extends IDataRenderer
-{
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex();
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value);
-
- /**
- * @return TListItemType the item type.
- */
- public function getItemType();
-
- /**
- * @param TListItemType the item type.
- */
- public function setItemType($value);
-}
-
-?>
+<?php
+/**
+ * TDataBoundControl class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataSourceControl');
+Prado::using('System.Web.UI.WebControls.TDataSourceView');
+Prado::using('System.Collections.TPagedDataSource');
+
+/**
+ * TDataBoundControl class.
+ *
+ * TDataBoundControl is the based class for controls that need to populate
+ * data from data sources. It provides basic properties and methods that allow
+ * the derived controls to associate with data sources and retrieve data from them.
+ *
+ * TBC....
+ *
+ * TDataBoundControl is equipped with paging capabilities. By setting
+ * {@link setAllowPaging AllowPaging} to true, the input data will be paged
+ * and only one page of data is actually populated into the data-bound control.
+ * This saves a lot of memory when dealing with larget datasets.
+ *
+ * To specify the number of data items displayed on each page, set
+ * the {@link setPageSize PageSize} property, and to specify which
+ * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
+ *
+ * When the size of the original data is too big to be loaded all in the memory,
+ * one can enable custom paging. In custom paging, the total number of data items
+ * is specified manually via {@link setVirtualItemCount VirtualItemCount},
+ * and the data source only needs to contain the current page of data. To enable
+ * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataBoundControl extends TWebControl
+{
+ private $_initialized=false;
+ private $_dataSource=null;
+ private $_requiresBindToNull=false;
+ private $_requiresDataBinding=false;
+ private $_prerendered=false;
+ private $_currentView=null;
+ private $_currentDataSource=null;
+ private $_currentViewValid=false;
+ private $_currentDataSourceValid=false;
+ private $_currentViewIsFromDataSourceID=false;
+ private $_parameters=null;
+ private $_isDataBound=false;
+
+ /**
+ * @return Traversable data source object, defaults to null.
+ */
+ public function getDataSource()
+ {
+ return $this->_dataSource;
+ }
+
+ /**
+ * Sets the data source object associated with the databound control.
+ * The data source must implement Traversable interface.
+ * If an array is given, it will be converted to xxx.
+ * If a string is given, it will be converted to xxx.
+ * @param Traversable|array|string data source object
+ */
+ public function setDataSource($value)
+ {
+ $this->_dataSource=$this->validateDataSource($value);
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return string ID path to the data source control. Defaults to empty.
+ */
+ public function getDataSourceID()
+ {
+ return $this->getViewState('DataSourceID','');
+ }
+
+ /**
+ * @param string ID path to the data source control. The data source
+ * control must be locatable via {@link TControl::findControl} call.
+ */
+ public function setDataSourceID($value)
+ {
+ $dsid=$this->getViewState('DataSourceID','');
+ if($dsid!=='' && $value==='')
+ $this->_requiresBindToNull=true;
+ $this->setViewState('DataSourceID',$value,'');
+ $this->onDataSourceChanged();
+ }
+
+ /**
+ * @return boolean if the databound control uses the data source specified
+ * by {@link setDataSourceID}, or it uses the data source object specified
+ * by {@link setDataSource}.
+ */
+ protected function getUsingDataSourceID()
+ {
+ return $this->getDataSourceID()!=='';
+ }
+
+ /**
+ * Sets {@link setRequiresDataBinding RequiresDataBinding} as true if the control is initialized.
+ * This method is invoked when either {@link setDataSource} or {@link setDataSourceID} is changed.
+ */
+ public function onDataSourceChanged()
+ {
+ $this->_currentViewValid=false;
+ $this->_currentDataSourceValid=false;
+ if($this->getInitialized())
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * @return boolean whether the databound control has been initialized.
+ * By default, the control is initialized after its viewstate has been restored.
+ */
+ protected function getInitialized()
+ {
+ return $this->_initialized;
+ }
+
+ /**
+ * Sets a value indicating whether the databound control is initialized.
+ * If initialized, any modification to {@link setDataSource DataSource} or
+ * {@link setDataSourceID DataSourceID} will set {@link setRequiresDataBinding RequiresDataBinding}
+ * as true.
+ * @param boolean a value indicating whether the databound control is initialized.
+ */
+ protected function setInitialized($value)
+ {
+ $this->_initialized=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether databind has been invoked in the previous page request
+ */
+ protected function getIsDataBound()
+ {
+ return $this->_isDataBound;
+ }
+
+ /**
+ * @param boolean if databind has been invoked in this page request
+ */
+ protected function setIsDataBound($value)
+ {
+ $this->_isDataBound=$value;
+ }
+
+ /**
+ * @return boolean whether a databind call is required (by the data bound control)
+ */
+ protected function getRequiresDataBinding()
+ {
+ return $this->_requiresDataBinding;
+ }
+
+ /**
+ * @return boolean whether paging is enabled. Defaults to false.
+ */
+ public function getAllowPaging()
+ {
+ return $this->getViewState('AllowPaging',false);
+ }
+
+ /**
+ * @param boolean whether paging is enabled
+ */
+ public function setAllowPaging($value)
+ {
+ $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the custom paging is enabled. Defaults to false.
+ */
+ public function getAllowCustomPaging()
+ {
+ return $this->getViewState('AllowCustomPaging',false);
+ }
+
+ /**
+ * Sets a value indicating whether the custom paging should be enabled.
+ * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
+ * property is used to determine the paging, and the data items in the
+ * {@link setDataSource DataSource} are considered to be in the current page.
+ * @param boolean whether the custom paging is enabled
+ */
+ public function setAllowCustomPaging($value)
+ {
+ $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ public function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer the number of data items on each page. Defaults to 10.
+ */
+ public function getPageSize()
+ {
+ return $this->getViewState('PageSize',10);
+ }
+
+ /**
+ * @param integer the number of data items on each page.
+ * @throws TInvalidDataValueException if the value is less than 1
+ */
+ public function setPageSize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
+ $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',1);
+ }
+
+ /**
+ * @return integer virtual number of data items in the data source. Defaults to 0.
+ * @see setAllowCustomPaging
+ */
+ public function getVirtualItemCount()
+ {
+ return $this->getViewState('VirtualItemCount',0);
+ }
+
+ /**
+ * @param integer virtual number of data items in the data source.
+ * @throws TInvalidDataValueException if the value is less than 0
+ * @see setAllowCustomPaging
+ */
+ public function setVirtualItemCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
+ $this->setViewState('VirtualItemCount',$value,0);
+ }
+
+ /**
+ * Sets a value indicating whether a databind call is required by the data bound control.
+ * If true and the control has been prerendered while it uses the data source
+ * specified by {@link setDataSourceID}, a databind call will be called by this method.
+ * @param boolean whether a databind call is required.
+ */
+ protected function setRequiresDataBinding($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ if($value && $this->_prerendered)
+ {
+ $this->_requiresDataBinding=true;
+ $this->ensureDataBound();
+ }
+ else
+ $this->_requiresDataBinding=$value;
+ }
+
+ /**
+ * Ensures any pending {@link dataBind} is called.
+ * This method calls {@link dataBind} if the data source is specified
+ * by {@link setDataSourceID} or if {@link getRequiresDataBinding RequiresDataBinding}
+ * is true.
+ */
+ protected function ensureDataBound()
+ {
+ if($this->_requiresDataBinding && ($this->getUsingDataSourceID() || $this->_requiresBindToNull))
+ {
+ $this->dataBind();
+ $this->_requiresBindToNull=false;
+ }
+ }
+
+ /**
+ * @return TPagedDataSource creates a paged data source
+ */
+ protected function createPagedDataSource()
+ {
+ $ds=new TPagedDataSource;
+ $ds->setCurrentPageIndex($this->getCurrentPageIndex());
+ $ds->setPageSize($this->getPageSize());
+ $ds->setAllowPaging($this->getAllowPaging());
+ $ds->setAllowCustomPaging($this->getAllowCustomPaging());
+ $ds->setVirtualItemCount($this->getVirtualItemCount());
+ return $ds;
+ }
+
+ /**
+ * Performs databinding.
+ * This method overrides the parent implementation by calling
+ * {@link performSelect} which fetches data from data source and does
+ * the actual binding work.
+ */
+ public function dataBind()
+ {
+ $this->setRequiresDataBinding(false);
+ $this->dataBindProperties();
+ $this->onDataBinding(null);
+
+ if(($view=$this->getDataSourceView())!==null)
+ $data=$view->select($this->getSelectParameters());
+ else
+ $data=null;
+
+ if($data instanceof Traversable)
+ {
+ if($this->getAllowPaging())
+ {
+ $ds=$this->createPagedDataSource();
+ $ds->setDataSource($data);
+ $this->setViewState('PageCount',$ds->getPageCount());
+ if($ds->getCurrentPageIndex()>=$ds->getPageCount())
+ {
+ $ds->setCurrentPageIndex($ds->getPageCount()-1);
+ $this->setCurrentPageIndex($ds->getCurrentPageIndex());
+ }
+ $this->performDataBinding($ds);
+ }
+ else
+ {
+ $this->clearViewState('PageCount');
+ $this->performDataBinding($data);
+ }
+ }
+ $this->setIsDataBound(true);
+ $this->onDataBound(null);
+ }
+
+ public function dataSourceViewChanged($sender,$param)
+ {
+ if(!$this->_ignoreDataSourceViewChanged)
+ $this->setRequiresDataBinding(true);
+ }
+
+ protected function getDataSourceView()
+ {
+ if(!$this->_currentViewValid)
+ {
+ if($this->_currentView && $this->_currentViewIsFromDataSourceID)
+ $this->_currentView->detachEventHandler('DataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ if(($dataSource=$this->determineDataSource())!==null)
+ {
+ if(($view=$dataSource->getView($this->getDataMember()))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datamember_invalid',$this->getDataMember());
+ if($this->_currentViewIsFromDataSourceID=$this->getUsingDataSourceID())
+ $view->attachEventHandler('OnDataSourceViewChanged',array($this,'dataSourceViewChanged'));
+ $this->_currentView=$view;
+ }
+ else
+ $this->_currentView=null;
+ $this->_currentViewValid=true;
+ }
+ return $this->_currentView;
+ }
+
+ protected function determineDataSource()
+ {
+ if(!$this->_currentDataSourceValid)
+ {
+ if(($dsid=$this->getDataSourceID())!=='')
+ {
+ if(($dataSource=$this->getNamingContainer()->findControl($dsid))===null)
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_inexistent',$dsid);
+ else if(!($dataSource instanceof IDataSource))
+ throw new TInvalidDataValueException('databoundcontrol_datasourceid_invalid',$dsid);
+ else
+ $this->_currentDataSource=$dataSource;
+ }
+ else if(($dataSource=$this->getDataSource())!==null)
+ $this->_currentDataSource=new TReadOnlyDataSource($dataSource,$this->getDataMember());
+ else
+ $this->_currentDataSource=null;
+ $this->_currentDataSourceValid=true;
+ }
+ return $this->_currentDataSource;
+ }
+
+ abstract protected function performDataBinding($data);
+
+ /**
+ * Raises <b>OnDataBound</b> event.
+ * This method should be invoked after a databind is performed.
+ * It is mainly used by framework and component developers.
+ */
+ public function onDataBound($param)
+ {
+ $this->raiseEvent('OnDataBound',$this,$param);
+ }
+
+ /**
+ * Sets page's <b>OnPreLoad</b> event handler as {@link pagePreLoad}.
+ * If viewstate is disabled and the current request is a postback,
+ * {@link setRequiresDataBinding RequiresDataBinding} will be set true.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $page=$this->getPage();
+ $page->attachEventHandler('OnPreLoad',array($this,'pagePreLoad'));
+ }
+
+ /**
+ * Sets {@link getInitialized} as true.
+ * This method is invoked when page raises <b>PreLoad</b> event.
+ * @param mixed event sender
+ * @param TEventParameter event parameter
+ */
+ public function pagePreLoad($sender,$param)
+ {
+ $this->_initialized=true;
+ $isPostBack=$this->getPage()->getIsPostBack();
+ if(!$isPostBack || ($isPostBack && (!$this->getEnableViewState(true) || !$this->getIsDataBound())))
+ $this->setRequiresDataBinding(true);
+ }
+
+ /**
+ * Ensures any pending databind is performed.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onPreRender($param)
+ {
+ $this->_prerendered=true;
+ $this->ensureDataBound();
+ parent::onPreRender($param);
+ }
+
+ /**
+ * Validates if the parameter is a valid data source.
+ * If it is a string or an array, it will be converted as a TList object.
+ * @param Traversable|array|string data source to be validated
+ * @return Traversable the data that is traversable
+ * @throws TInvalidDataTypeException if the data is neither null nor Traversable
+ */
+ protected function validateDataSource($value)
+ {
+ if(is_string($value))
+ {
+ $list=new TList;
+ foreach(TPropertyValue::ensureArray($value) as $key=>$value)
+ {
+ if(is_array($value))
+ $list->add($value);
+ else
+ $list->add(array($value,is_string($key)?$key:$value));
+ }
+ return $list;
+ }
+ else if(is_array($value))
+ return new TMap($value);
+ else if($value instanceof TDbDataReader) {
+ // read array from TDbDataReader since it's forward-only stream and can only be traversed once
+ return $value->readAll();
+ }
+ else if(($value instanceof Traversable) || $value===null)
+ return $value;
+ else
+ throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
+ }
+
+ public function getDataMember()
+ {
+ return $this->getViewState('DataMember','');
+ }
+
+ public function setDataMember($value)
+ {
+ $this->setViewState('DataMember',$value,'');
+ }
+
+ public function getSelectParameters()
+ {
+ if(!$this->_parameters)
+ $this->_parameters=new TDataSourceSelectParameters;
+ return $this->_parameters;
+ }
+}
+
+
+/**
+ * TListItemType class.
+ * TListItemType defines the enumerable type for the possible types
+ * that databound list items could take.
+ *
+ * The following enumerable values are defined:
+ * - Header: header item
+ * - Footer: footer item
+ * - Item: content item (neither header nor footer)
+ * - Separator: separator between items
+ * - AlternatingItem: alternating content item
+ * - EditItem: content item in edit mode
+ * - SelectedItem: selected content item
+ * - Pager: pager
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TListItemType extends TEnumerable
+{
+ const Header='Header';
+ const Footer='Footer';
+ const Item='Item';
+ const Separator='Separator';
+ const AlternatingItem='AlternatingItem';
+ const EditItem='EditItem';
+ const SelectedItem='SelectedItem';
+ const Pager='Pager';
+}
+
+
+/**
+ * IItemDataRenderer interface.
+ *
+ * IItemDataRenderer defines the interface that an item renderer
+ * needs to implement. Besides the {@link getData Data} property, a list item
+ * renderer also needs to provide {@link getItemIndex ItemIndex} and
+ * {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+interface IItemDataRenderer extends IDataRenderer
+{
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex();
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value);
+
+ /**
+ * @return TListItemType the item type.
+ */
+ public function getItemType();
+
+ /**
+ * @param TListItemType the item type.
+ */
+ public function setItemType($value);
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TDataGrid.php b/framework/Web/UI/WebControls/TDataGrid.php
index 2af66b33..2e2c5252 100644
--- a/framework/Web/UI/WebControls/TDataGrid.php
+++ b/framework/Web/UI/WebControls/TDataGrid.php
@@ -1,2258 +1,2258 @@
-<?php
-/**
- * TDataGrid related class files.
- * This file contains the definition of the following classes:
- * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection,
- * TDataGridPagerStyle, TDataGridItemEventParameter,
- * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter,
- * TDataGridPageChangedEventParameter
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-Prado::using('System.Collections.TPagedDataSource');
-Prado::using('System.Collections.TDummyDataSource');
-Prado::using('System.Web.UI.WebControls.TTable');
-Prado::using('System.Web.UI.WebControls.TPanel');
-Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
-
-/**
- * TDataGrid class
- *
- * TDataGrid represents a data bound and updatable grid control.
- *
- * To populate data into the datagrid, sets its {@link setDataSource DataSource}
- * to a tabular data source and call {@link dataBind()}.
- * Each row of data will be represented by an item in the {@link getItems Items}
- * collection of the datagrid.
- *
- * An item can be at one of three states: browsing, selected and edit.
- * The state determines how the item will be displayed. For example, if an item
- * is in edit state, it may be displayed as a table row with input text boxes
- * if the columns are of type {@link TBoundColumn}; and if in browsing state,
- * they are displayed as static text.
- *
- * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
- * or {@link setSelectedItemIndex SelectedItemIndex} property.
- *
- * Each datagrid item has a {@link TDataGridItem::getItemType type}
- * which tells the position and state of the item in the datalist. An item in the header
- * of the repeater is of type Header. A body item may be of either
- * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
- * index is odd or even, whether it is being selected or edited.
- *
- * A datagrid is specified with a list of columns. Each column specifies how the corresponding
- * table column will be displayed. For example, the header/footer text of that column,
- * the cells in that column, and so on. The following column types are currently
- * provided by the framework,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * There are three ways to specify columns for a datagrid.
- * <ul>
- * <li>Automatically generated based on data source.
- * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
- * a list of columns will be automatically generated based on the schema of the data source.
- * Each column corresponds to a column of the data.</li>
- * <li>Specified in template. For example,
- * <code>
- * <com:TDataGrid ...>
- * <com:TBoundColumn .../>
- * <com:TEditCommandColumn .../>
- * </com:TDataGrid>
- * </code>
- * </li>
- * <li>Manually created in code. Columns can be manipulated via
- * the {@link setColumns Columns} property of the datagrid. For example,
- * <code>
- * $column=new TBoundColumn;
- * $datagrid->Columns[]=$column;
- * </code>
- * </li>
- * </ul>
- * Note, automatically generated columns cannot be accessed via
- * the {@link getColumns Columns} property.
- *
- * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
- * is set to true, a column with nonempty {@link setSortExpression SortExpression}
- * will have its header text displayed as a clickable link button.
- * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
- * event. You can respond to this event, sort the data source according
- * to the event parameter, and then invoke {@link databind()} on the datagrid
- * to show to end users the sorted data.
- *
- * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
- * is set to true, a pager will be displayed on top and/or bottom of the table.
- * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
- * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
- * event. You can respond to this event, specify the page to be displayed by
- * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property,
- * and then invoke {@link databind()} on the datagrid to show to end users
- * a new page of data.
- *
- * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
- * datasource. The number of pages {@link getPageCount PageCount} is calculated based
- * the item number and the {@link setPageSize PageSize} property.
- * The datagrid will manage which section of the data source to be displayed
- * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
- * The second approach calculates the page number based on the
- * {@link setVirtualItemCount VirtualItemCount} property and
- * the {@link setPageSize PageSize} property. The datagrid will always
- * display from the beginning of the datasource up to the number of
- * {@link setPageSize PageSize} data items. This approach is especially
- * useful when the datasource may contain too many data items to be managed by
- * the datagrid efficiently.
- *
- * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
- * event, the event will be bubbled up to the datagrid control.
- * If the event's command name is recognizable by the datagrid control,
- * a corresponding item event will be raised. The following item events will be
- * raised upon a specific command:
- * - OnEditCommand, if CommandName=edit
- * - OnCancelCommand, if CommandName=cancel
- * - OnSelectCommand, if CommandName=select
- * - OnDeleteCommand, if CommandName=delete
- * - OnUpdateCommand, if CommandName=update
- * - onPageIndexChanged, if CommandName=page
- * - OnSortCommand, if CommandName=sort
- * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
- * the above specific command events.
- *
- * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
- * every newly created datagrid item. You can respond to this event to customize
- * the content or style of the newly created item.
- *
- * Note, the data bound to the datagrid are reset to null after databinding.
- * There are several ways to access the data associated with a datagrid row:
- * - Access the data in {@link onItemDataBound OnItemDataBound} event
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datagrid row and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the data in viewstate and get it back during postbacks.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGrid extends TBaseDataList implements INamingContainer
-{
- /**
- * datagrid item types
- * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
- */
- const IT_HEADER='Header';
- const IT_FOOTER='Footer';
- const IT_ITEM='Item';
- const IT_SEPARATOR='Separator';
- const IT_ALTERNATINGITEM='AlternatingItem';
- const IT_EDITITEM='EditItem';
- const IT_SELECTEDITEM='SelectedItem';
- const IT_PAGER='Pager';
-
- /**
- * Command name that TDataGrid understands.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
- const CMD_SORT='Sort';
- const CMD_PAGE='Page';
- const CMD_PAGE_NEXT='Next';
- const CMD_PAGE_PREV='Previous';
- const CMD_PAGE_FIRST='First';
- const CMD_PAGE_LAST='Last';
-
- /**
- * @var TDataGridColumnCollection manually created column collection
- */
- private $_columns=null;
- /**
- * @var TDataGridColumnCollection automatically created column collection
- */
- private $_autoColumns=null;
- /**
- * @var TList all columns including both manually and automatically created columns
- */
- private $_allColumns=null;
- /**
- * @var TDataGridItemCollection datagrid item collection
- */
- private $_items=null;
- /**
- * @var TDataGridItem header item
- */
- private $_header=null;
- /**
- * @var TDataGridItem footer item
- */
- private $_footer=null;
- /**
- * @var TPagedDataSource paged data source object
- */
- private $_pagedDataSource=null;
- private $_topPager=null;
- private $_bottomPager=null;
- /**
- * @var ITemplate template used when empty data is bounded
- */
- private $_emptyTemplate=null;
- /**
- * @var boolean whether empty template is effective
- */
- private $_useEmptyTemplate=false;
-
- /**
- * @return string tag name (table) of the datagrid
- */
- protected function getTagName()
- {
- return 'table';
- }
-
- /**
- * @return string Name of the class used in AutoGenerateColumns mode
- */
- protected function getAutoGenerateColumnName()
- {
- return 'TBoundColumn';
- }
-
- /**
- * Adds objects parsed in template to datagrid.
- * Datagrid columns are added into {@link getColumns Columns} collection.
- * @param mixed object parsed in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TDataGridColumn)
- $this->getColumns()->add($object);
- else
- parent::addParsedObject($object); // this is needed by EmptyTemplate
- }
-
- /**
- * @return TDataGridColumnCollection manually specified datagrid columns
- */
- public function getColumns()
- {
- if(!$this->_columns)
- $this->_columns=new TDataGridColumnCollection($this);
- return $this->_columns;
- }
-
- /**
- * @return TDataGridColumnCollection automatically generated datagrid columns
- */
- public function getAutoColumns()
- {
- if(!$this->_autoColumns)
- $this->_autoColumns=new TDataGridColumnCollection($this);
- return $this->_autoColumns;
- }
-
- /**
- * @return TDataGridItemCollection datagrid item collection
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataGridItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by datagrid.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * @return string the URL of the background image for the datagrid
- */
- public function getBackImageUrl()
- {
- return $this->getStyle()->getBackImageUrl();
- }
-
- /**
- * @param string the URL of the background image for the datagrid
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * @return TTableItemStyle the style for every item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TDataGridPagerStyle the style for pager
- */
- public function getPagerStyle()
- {
- if(($style=$this->getViewState('PagerStyle',null))===null)
- {
- $style=new TDataGridPagerStyle;
- $this->setViewState('PagerStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for thead element, if any
- * @since 3.1.1
- */
- public function getTableHeadStyle()
- {
- if(($style=$this->getViewState('TableHeadStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableHeadStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tbody element, if any
- * @since 3.1.1
- */
- public function getTableBodyStyle()
- {
- if(($style=$this->getViewState('TableBodyStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableBodyStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style for tfoot element, if any
- * @since 3.1.1
- */
- public function getTableFootStyle()
- {
- if(($style=$this->getViewState('TableFootStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('TableFootStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string caption for the datagrid
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string caption for the datagrid
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',$value,'');
- }
-
- /**
- * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
- }
-
- /**
- * @param TTableCaptionAlign datagrid caption alignment. Valid values include
- */
- public function setCaptionAlign($value)
- {
- $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
- }
-
- /**
- * @return TDataGridItem the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TDataGridItem the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
- */
- public function getTopPager()
- {
- return $this->_topPager;
- }
-
- /**
- * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
- */
- public function getBottomPager()
- {
- return $this->_bottomPager;
- }
-
- /**
- * @return TDataGridItem the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if($item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TDataGridItem the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return boolean whether sorting is enabled. Defaults to false.
- */
- public function getAllowSorting()
- {
- return $this->getViewState('AllowSorting',false);
- }
-
- /**
- * @param boolean whether sorting is enabled
- */
- public function setAllowSorting($value)
- {
- $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
- */
- public function getAutoGenerateColumns()
- {
- return $this->getViewState('AutoGenerateColumns',true);
- }
-
- /**
- * @param boolean whether datagrid columns should be automatically generated
- */
- public function setAutoGenerateColumns($value)
- {
- $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the header should be displayed. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether the header should be displayed
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be displayed. Defaults to false.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',false);
- }
-
- /**
- * @param boolean whether the footer should be displayed
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datagrid
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datagrid
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * {@link TDataGridItem} child controls.
- * If the event parameter is {@link TDataGridCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataGridCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- $this->setSelectedItemIndex($param->getItem()->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_SORT)===0)
- {
- $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE)===0)
- {
- $p=$param->getCommandParameter();
- if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
- $pageIndex=$this->getCurrentPageIndex()+1;
- else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
- $pageIndex=$this->getCurrentPageIndex()-1;
- else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
- $pageIndex=0;
- else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
- $pageIndex=$this->getPageCount()-1;
- else
- $pageIndex=TPropertyValue::ensureInteger($p)-1;
- $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- }
- return false;
- }
-
- /**
- * Raises <b>OnCancelCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>cancel</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnDeleteCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>delete</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnEditCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>edit</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnSortCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>sort</b> command name.
- * @param TDataGridSortCommandEventParameter event parameter
- */
- public function onSortCommand($param)
- {
- $this->raiseEvent('OnSortCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnUpdateCommand</b> event.
- * This method is invoked when a button control raises <b>OnCommand</b> event
- * with <b>update</b> command name.
- * @param TDataGridCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked right after a datagrid item is created and before
- * added to page hierarchy.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnPagerCreated</b> event.
- * This method is invoked right after a datagrid pager is created and before
- * added to page hierarchy.
- * @param TDataGridPagerEventParameter event parameter
- */
- public function onPagerCreated($param)
- {
- $this->raiseEvent('OnPagerCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked for each datagrid item after it performs
- * databinding.
- * @param TDataGridItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnPageIndexChanged</b> event.
- * This method is invoked when current page is changed.
- * @param TDataGridPageChangedEventParameter event parameter
- */
- public function onPageIndexChanged($param)
- {
- $this->raiseEvent('OnPageIndexChanged',$this,$param);
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if(!$this->getEnableViewState(true))
- return;
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- if($this->_autoColumns)
- {
- $state=array();
- foreach($this->_autoColumns as $column)
- $state[]=$column->saveState();
- $this->setViewState('AutoColumns',$state,array());
- }
- else
- $this->clearViewState('AutoColumns');
- if($this->_columns)
- {
- $state=array();
- foreach($this->_columns as $column)
- $state[]=$column->saveState();
- $this->setViewState('Columns',$state,array());
- }
- else
- $this->clearViewState('Columns');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getEnableViewState(true))
- return;
- if(!$this->getIsDataBound())
- {
- $state=$this->getViewState('AutoColumns',array());
- if(!empty($state))
- {
- $this->_autoColumns=new TDataGridColumnCollection($this);
- foreach($state as $st)
- {
- $column=new $this->AutoGenerateColumnName;
- $column->loadState($st);
- $this->_autoColumns->add($column);
- }
- }
- else
- $this->_autoColumns=null;
- $state=$this->getViewState('Columns',array());
- if($this->_columns && $this->_columns->getCount()===count($state))
- {
- $i=0;
- foreach($this->_columns as $column)
- {
- $column->loadState($state[$i]);
- $i++;
- }
- }
- $this->restoreGridFromViewState();
- }
- }
-
- /**
- * Clears up all items in the datagrid.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- $this->_topPager=null;
- $this->_bottomPager=null;
- $this->_useEmptyTemplate=false;
- }
-
- /**
- * Restores datagrid content from viewstate.
- */
- protected function restoreGridFromViewState()
- {
- $this->reset();
-
- $allowPaging=$this->getAllowPaging();
-
- $itemCount=$this->getViewState('ItemCount',0);
- $dsIndex=$this->getViewState('DataSourceIndex',0);
-
- $columns=new TList($this->getColumns());
- $columns->mergeWith($this->_autoColumns);
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- for($index=0;$index<$itemCount;++$index)
- {
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- }
- }
-
- /**
- * Performs databinding to populate datagrid items from data source.
- * This method is invoked by {@link dataBind()}.
- * You may override this function to provide your own way of data population.
- * @param Traversable the bound data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
-
- // get all columns
- if($this->getAutoGenerateColumns())
- {
- $columns=new TList($this->getColumns());
- $autoColumns=$this->createAutoColumns($data);
- $columns->mergeWith($autoColumns);
- }
- else
- $columns=$this->getColumns();
- $this->_allColumns=$columns;
-
- $items=$this->getItems();
-
- $index=0;
- $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
- $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
- $this->setViewState('DataSourceIndex',$dsIndex,0);
- if($columns->getCount())
- {
- foreach($columns as $column)
- $column->initialize();
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$row)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($row,$keyField));
- else
- $keys->add($key);
- if($index===0)
- {
- if($allowPaging)
- $this->_topPager=$this->createPager();
- $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
- }
- if($index===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($index===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else if($index % 2)
- $itemType=TListItemType::AlternatingItem;
- else
- $itemType=TListItemType::Item;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
- $index++;
- $dsIndex++;
- }
- if($index>0)
- {
- $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
- if($allowPaging)
- $this->_bottomPager=$this->createPager();
- }
- }
- $this->setViewState('ItemCount',$index,0);
- if(!$dsIndex && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- $this->dataBindChildren();
- }
- }
-
- /**
- * Merges consecutive cells who have the same text.
- * @since 3.1.1
- */
- private function groupCells()
- {
- if(($columns=$this->_allColumns)===null)
- return;
- $items=$this->getItems();
- foreach($columns as $id=>$column)
- {
- if(!$column->getEnableCellGrouping())
- continue;
- $prevCell=null;
- $prevCellText=null;
- foreach($items as $item)
- {
- $itemType=$item->getItemType();
- $cell=$item->getCells()->itemAt($id);
- if(!$cell->getVisible())
- continue;
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- if(($cellText=$this->getCellText($cell))==='')
- {
- $prevCell=null;
- $prevCellText=null;
- continue;
- }
- if($prevCell===null || $prevCellText!==$cellText)
- {
- $prevCell=$cell;
- $prevCellText=$cellText;
- }
- else
- {
- if(($rowSpan=$prevCell->getRowSpan())===0)
- $rowSpan=1;
- $prevCell->setRowSpan($rowSpan+1);
- $cell->setVisible(false);
- }
- }
- }
- }
- }
-
- private function getCellText($cell)
- {
- if(($data=$cell->getText())==='' && $cell->getHasControls())
- {
- $controls=$cell->getControls();
- foreach($controls as $control)
- {
- if($control instanceof IDataRenderer)
- return $control->getData();
- }
- }
- return $data;
- }
-
- /**
- * Creates a datagrid item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TDataGridItem created data list item
- */
- protected function createItem($itemIndex,$dataSourceIndex,$itemType)
- {
- return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
- }
-
- private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
- {
- $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
- $this->initializeItem($item,$columns);
- $param=new TDataGridItemEventParameter($item);
- if($dataBind)
- {
- $item->setDataItem($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- }
- else
- {
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- }
- return $item;
- }
-
- /**
- * Initializes a datagrid item and cells inside it
- * @param TDataGrid datagrid item to be initialized
- * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
- */
- protected function initializeItem($item,$columns)
- {
- $cells=$item->getCells();
- $itemType=$item->getItemType();
- $index=0;
- foreach($columns as $column)
- {
- if($itemType===TListItemType::Header)
- $cell=new TTableHeaderCell;
- else
- $cell=new TTableCell;
- if(($id=$column->getID())!=='')
- $item->registerObject($id,$cell);
- $cells->add($cell);
- $column->initializeCell($cell,$index,$itemType);
- $index++;
- }
- }
-
- protected function createPager()
- {
- $pager=new TDataGridPager($this);
- $this->buildPager($pager);
- $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
- $this->getControls()->add($pager);
- return $pager;
- }
-
- /**
- * Builds the pager content based on pager style.
- * @param TDataGridPager the container for the pager
- */
- protected function buildPager($pager)
- {
- switch($this->getPagerStyle()->getMode())
- {
- case TDataGridPagerMode::NextPrev:
- $this->buildNextPrevPager($pager);
- break;
- case TDataGridPagerMode::Numeric:
- $this->buildNumericPager($pager);
- break;
- }
- }
-
- /**
- * Creates a pager button.
- * Depending on the button type, a TLinkButton or a TButton may be created.
- * If it is enabled (clickable), its command name and parameter will also be set.
- * Derived classes may override this method to create additional types of buttons, such as TImageButton.
- * @param mixed the container pager instance of TActiveDatagridPager
- * @param string button type, either LinkButton or PushButton
- * @param boolean whether the button should be enabled
- * @param string caption of the button
- * @param string CommandName corresponding to the OnCommand event of the button
- * @param string CommandParameter corresponding to the OnCommand event of the button
- * @return mixed the button instance
- */
- protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
- {
- if($buttonType===TDataGridPagerButtonType::LinkButton)
- {
- if($enabled)
- $button=new TLinkButton;
- else
- {
- $button=new TLabel;
- $button->setText($text);
- return $button;
- }
- }
- else
- {
- $button=new TButton;
- if(!$enabled)
- $button->setEnabled(false);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCommandParameter($commandParameter);
- $button->setCausesValidation(false);
- return $button;
- }
-
- /**
- * Builds a next-prev pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNextPrevPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $currentPageIndex=$this->getCurrentPageIndex();
- if($currentPageIndex===0)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- $controls->add("\n");
- }
-
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
- $controls->add($label);
- }
- else
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
-
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
- $controls->add($button);
- }
- $controls->add("\n");
- if($currentPageIndex===$this->getPageCount()-1)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
- $controls->add($label);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
- $controls->add($label);
- }
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a numeric pager
- * @param TDataGridPager the container for the pager
- */
- protected function buildNumericPager($pager)
- {
- $style=$this->getPagerStyle();
- $buttonType=$style->getButtonType();
- $controls=$pager->getControls();
- $pageCount=$this->getPageCount();
- $pageIndex=$this->getCurrentPageIndex()+1;
- $maxButtonCount=$style->getPageButtonCount();
- $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
- $startPageIndex=1;
- $endPageIndex=$buttonCount;
- if($pageIndex>$endPageIndex)
- {
- $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
- if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
- $endPageIndex=$pageCount;
- if($endPageIndex-$startPageIndex+1<$maxButtonCount)
- {
- if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
- $startPageIndex=1;
- }
- }
-
- if($startPageIndex>1)
- {
- if(($text=$style->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
- $controls->add($button);
- $controls->add("\n");
- }
- $prevPageIndex=$startPageIndex-1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
- $controls->add($button);
- $controls->add("\n");
- }
-
- for($i=$startPageIndex;$i<=$endPageIndex;++$i)
- {
- if($i===$pageIndex)
- {
- $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
- $controls->add($label);
- }
- else
- {
- $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
- $controls->add($button);
- }
- if($i<$endPageIndex)
- $controls->add("\n");
- }
-
- if($pageCount>$endPageIndex)
- {
- $controls->add("\n");
- $nextPageIndex=$endPageIndex+1;
- $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
- $controls->add($button);
- if(($text=$style->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
- $controls->add($button);
- }
- }
- }
-
- /**
- * Automatically generates datagrid columns based on datasource schema
- * @param Traversable data source bound to the datagrid
- * @return TDataGridColumnCollection
- */
- protected function createAutoColumns($dataSource)
- {
- if(!$dataSource)
- return null;
- $autoColumns=$this->getAutoColumns();
- $autoColumns->clear();
- foreach($dataSource as $row)
- {
- foreach($row as $key=>$value)
- {
- $column=new $this->AutoGenerateColumnName;
- if(is_string($key))
- {
- $column->setHeaderText($key);
- $column->setDataField($key);
- $column->setSortExpression($key);
- $autoColumns->add($column);
- }
- else
- {
- $column->setHeaderText(TListItemType::Item);
- $column->setDataField($key);
- $column->setSortExpression(TListItemType::Item);
- $autoColumns->add($column);
- }
- }
- break;
- }
- return $autoColumns;
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- $headerStyle=$this->getViewState('HeaderStyle',null);
- $footerStyle=$this->getViewState('FooterStyle',null);
- $pagerStyle=$this->getViewState('PagerStyle',null);
- $separatorStyle=$this->getViewState('SeparatorStyle',null);
-
- foreach($this->getControls() as $index=>$item)
- {
- if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
- continue;
- $itemType=$item->getItemType();
- switch($itemType)
- {
- case TListItemType::Header:
- if($headerStyle)
- $item->getStyle()->mergeWith($headerStyle);
- if(!$this->getShowHeader())
- $item->setVisible(false);
- break;
- case TListItemType::Footer:
- if($footerStyle)
- $item->getStyle()->mergeWith($footerStyle);
- if(!$this->getShowFooter())
- $item->setVisible(false);
- break;
- case TListItemType::Separator:
- if($separatorStyle)
- $item->getStyle()->mergeWith($separatorStyle);
- break;
- case TListItemType::Item:
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- break;
- case TListItemType::AlternatingItem:
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- break;
- case TListItemType::SelectedItem:
- if($selectedItemStyle)
- $item->getStyle()->mergeWith($selectedItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::EditItem:
- if($editItemStyle)
- $item->getStyle()->mergeWith($editItemStyle);
- if($index % 2==1)
- {
- if($itemStyle)
- $item->getStyle()->mergeWith($itemStyle);
- }
- else
- {
- if($alternatingItemStyle)
- $item->getStyle()->mergeWith($alternatingItemStyle);
- }
- break;
- case TListItemType::Pager:
- if($pagerStyle)
- {
- $item->getStyle()->mergeWith($pagerStyle);
- if($index===0)
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- else
- {
- if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
- $item->setVisible(false);
- }
- }
- break;
- default:
- break;
- }
- if($this->_columns && $itemType!==TListItemType::Pager)
- {
- $n=$this->_columns->getCount();
- $cells=$item->getCells();
- for($i=0;$i<$n;++$i)
- {
- $cell=$cells->itemAt($i);
- $column=$this->_columns->itemAt($i);
- if(!$column->getVisible())
- $cell->setVisible(false);
- else
- {
- if($itemType===TListItemType::Header)
- $style=$column->getHeaderStyle(false);
- else if($itemType===TListItemType::Footer)
- $style=$column->getFooterStyle(false);
- else
- $style=$column->getItemStyle(false);
- if($style!==null)
- $cell->getStyle()->mergeWith($style);
- }
- }
- }
- }
- }
-
- /**
- * Renders the openning tag for the datagrid control which will render table caption if present.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($caption=$this->getCaption())!=='')
- {
- if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
- $writer->addAttribute('align',strtolower($align));
- $writer->renderBeginTag('caption');
- $writer->write($caption);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the datagrid.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- $this->groupCells();
- if($this->_useEmptyTemplate)
- {
- $control=new TWebControl;
- $control->setID($this->getClientID());
- $control->copyBaseAttributes($this);
- if($this->getHasStyle())
- $control->getStyle()->copyFrom($this->getStyle());
- $control->renderBeginTag($writer);
- $this->renderContents($writer);
- $control->renderEndTag($writer);
- }
- else if($this->getViewState('ItemCount',0)>0)
- {
- $this->applyItemStyles();
- if($this->_topPager)
- {
- $this->_topPager->renderControl($writer);
- $writer->writeLine();
- }
- $this->renderTable($writer);
- if($this->_bottomPager)
- {
- $writer->writeLine();
- $this->_bottomPager->renderControl($writer);
- }
- }
- }
- }
-
- /**
- * Renders the tabular data.
- * @param THtmlWriter writer
- */
- protected function renderTable($writer)
- {
- $this->renderBeginTag($writer);
- if($this->_header && $this->_header->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableHeadStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('thead');
- $this->_header->render($writer);
- $writer->renderEndTag();
- }
- $writer->writeLine();
- if($style=$this->getViewState('TableBodyStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tbody');
- foreach($this->getItems() as $item)
- $item->renderControl($writer);
- $writer->renderEndTag();
-
- if($this->_footer && $this->_footer->getVisible())
- {
- $writer->writeLine();
- if($style=$this->getViewState('TableFootStyle',null))
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('tfoot');
- $this->_footer->render($writer);
- $writer->renderEndTag();
- }
-
- $writer->writeLine();
- $this->renderEndTag($writer);
- }
-}
-
-/**
- * TDataGridItemEventParameter class
- *
- * TDataGridItemEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemEventParameter extends TEventParameter
-{
- /**
- * The TDataGridItem control responsible for the event.
- * @var TDataGridItem
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item related with the corresponding event
- */
- public function __construct(TDataGridItem $item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TDataGridItem datagrid item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataGridPagerEventParameter class
- *
- * TDataGridPagerEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
- * The {@link getPager Pager} property indicates the datagrid pager related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerEventParameter extends TEventParameter
-{
- /**
- * The TDataGridPager control responsible for the event.
- * @var TDataGridPager
- */
- protected $_pager=null;
-
- /**
- * Constructor.
- * @param TDataGridPager datagrid pager related with the corresponding event
- */
- public function __construct(TDataGridPager $pager)
- {
- $this->_pager=$pager;
- }
-
- /**
- * @return TDataGridPager datagrid pager related with the corresponding event
- */
- public function getPager()
- {
- return $this->_pager;
- }
-}
-
-/**
- * TDataGridCommandEventParameter class
- *
- * TDataGridCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getItem Item} property indicates the datagrid item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TDataGridItem the TDataGridItem control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>Command</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TDataGridItem datagrid item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TDataGridItem the TDataGridItem control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>Command</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataGridSortCommandEventParameter class
- *
- * TDataGridSortCommandEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
- * gives the sort expression carried with the sort command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridSortCommandEventParameter extends TEventParameter
-{
- /**
- * @var string sort expression
- */
- private $_sortExpression='';
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param TDataGridCommandEventParameter command event parameter
- */
- public function __construct($source,TDataGridCommandEventParameter $param)
- {
- $this->_source=$source;
- $this->_sortExpression=$param->getCommandParameter();
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return string sort expression
- */
- public function getSortExpression()
- {
- return $this->_sortExpression;
- }
-}
-
-/**
- * TDataGridPageChangedEventParameter class
- *
- * TDataGridPageChangedEventParameter encapsulates the parameter data for
- * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
- * returns the new page index carried with the page command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPageChangedEventParameter extends TEventParameter
-{
- /**
- * @var integer new page index
- */
- private $_newIndex;
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param integer new page index
- */
- public function __construct($source,$newPageIndex)
- {
- $this->_source=$source;
- $this->_newIndex=$newPageIndex;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return integer new page index
- */
- public function getNewPageIndex()
- {
- return $this->_newIndex;
- }
-}
-
-/**
- * TDataGridItem class
- *
- * A TDataGridItem control represents an item in the {@link TDataGrid} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
- * gives the index of the item from the bound data source.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItem extends TTableRow implements INamingContainer
-{
- /**
- * @var integer index of the data item in the Items collection of datagrid
- */
- private $_itemIndex='';
- /**
- * @var integer index of the item from the bound data source
- */
- private $_dataSourceIndex=0;
- /**
- * type of the TDataGridItem
- * @var string
- */
- private $_itemType='';
- /**
- * value of the data item
- * @var mixed
- */
- private $_data=null;
-
- /**
- * Constructor.
- * @param integer zero-based index of the item in the item collection of datagrid
- * @param TListItemType item type
- */
- public function __construct($itemIndex,$dataSourceIndex,$itemType)
- {
- $this->_itemIndex=$itemIndex;
- $this->_dataSourceIndex=$dataSourceIndex;
- $this->setItemType($itemType);
- if($itemType===TListItemType::Header)
- $this->setTableSection(TTableRowSection::Header);
- else if($itemType===TListItemType::Footer)
- $this->setTableSection(TTableRowSection::Footer);
- }
-
- /**
- * @return TListItemType item type.
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datagrid
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * @return integer the index of the datagrid item from the bound data source
- */
- public function getDataSourceIndex()
- {
- return $this->_dataSourceIndex;
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-
-/**
- * TDataGridPager class.
- *
- * TDataGridPager represents a datagrid pager.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPager extends TPanel implements INamingContainer
-{
- private $_dataGrid;
-
- /**
- * Constructor.
- * @param TDataGrid datagrid object
- */
- public function __construct($dataGrid)
- {
- $this->_dataGrid=$dataGrid;
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * @return TDataGrid the datagrid owning this pager
- */
- public function getDataGrid()
- {
- return $this->_dataGrid;
- }
-
- /**
- * @return string item type.
- */
- public function getItemType()
- {
- return TListItemType::Pager;
- }
-}
-
-
-/**
- * TDataGridItemCollection class.
- *
- * TDataGridItemCollection represents a collection of data grid items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TDataGridItem.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridItem)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
- }
-}
-
-/**
- * TDataGridColumnCollection class.
- *
- * TDataGridColumnCollection represents a collection of data grid columns.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridColumnCollection extends TList
-{
- /**
- * the control that owns this collection.
- * @var TControl
- */
- private $_o;
-
- /**
- * Constructor.
- * @param TDataGrid the control that owns this collection.
- */
- public function __construct(TDataGrid $owner)
- {
- $this->_o=$owner;
- }
-
- /**
- * @return TDataGrid the control that owns this collection.
- */
- protected function getOwner()
- {
- return $this->_o;
- }
-
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TDataGridColumn.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TDataGridColumn)
- {
- $item->setOwner($this->_o);
- parent::insertAt($index,$item);
- }
- else
- throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
- }
-}
-
-/**
- * TDataGridPagerMode class.
- * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
- *
- * The following enumerable values are defined:
- * - NextPrev: pager buttons are displayed as next and previous pages
- * - Numeric: pager buttons are displayed as numeric page numbers
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerMode extends TEnumerable
-{
- const NextPrev='NextPrev';
- const Numeric='Numeric';
-}
-
-
-/**
- * TDataGridPagerButtonType class.
- * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form submit buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerButtonType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
-}
-
-
-/**
- * TDataGridPagerPosition class.
- * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
- *
- * The following enumerable values are defined:
- * - Bottom: pager appears only at the bottom of the data grid.
- * - Top: pager appears only at the top of the data grid.
- * - TopAndBottom: pager appears on both top and bottom of the data grid.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDataGridPagerPosition extends TEnumerable
-{
- const Bottom='Bottom';
- const Top='Top';
- const TopAndBottom='TopAndBottom';
-}
-
+<?php
+/**
+ * TDataGrid related class files.
+ * This file contains the definition of the following classes:
+ * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection,
+ * TDataGridPagerStyle, TDataGridItemEventParameter,
+ * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter,
+ * TDataGridPageChangedEventParameter
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+Prado::using('System.Collections.TPagedDataSource');
+Prado::using('System.Collections.TDummyDataSource');
+Prado::using('System.Web.UI.WebControls.TTable');
+Prado::using('System.Web.UI.WebControls.TPanel');
+Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
+
+/**
+ * TDataGrid class
+ *
+ * TDataGrid represents a data bound and updatable grid control.
+ *
+ * To populate data into the datagrid, sets its {@link setDataSource DataSource}
+ * to a tabular data source and call {@link dataBind()}.
+ * Each row of data will be represented by an item in the {@link getItems Items}
+ * collection of the datagrid.
+ *
+ * An item can be at one of three states: browsing, selected and edit.
+ * The state determines how the item will be displayed. For example, if an item
+ * is in edit state, it may be displayed as a table row with input text boxes
+ * if the columns are of type {@link TBoundColumn}; and if in browsing state,
+ * they are displayed as static text.
+ *
+ * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
+ * or {@link setSelectedItemIndex SelectedItemIndex} property.
+ *
+ * Each datagrid item has a {@link TDataGridItem::getItemType type}
+ * which tells the position and state of the item in the datalist. An item in the header
+ * of the repeater is of type Header. A body item may be of either
+ * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
+ * index is odd or even, whether it is being selected or edited.
+ *
+ * A datagrid is specified with a list of columns. Each column specifies how the corresponding
+ * table column will be displayed. For example, the header/footer text of that column,
+ * the cells in that column, and so on. The following column types are currently
+ * provided by the framework,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * There are three ways to specify columns for a datagrid.
+ * <ul>
+ * <li>Automatically generated based on data source.
+ * By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
+ * a list of columns will be automatically generated based on the schema of the data source.
+ * Each column corresponds to a column of the data.</li>
+ * <li>Specified in template. For example,
+ * <code>
+ * <com:TDataGrid ...>
+ * <com:TBoundColumn .../>
+ * <com:TEditCommandColumn .../>
+ * </com:TDataGrid>
+ * </code>
+ * </li>
+ * <li>Manually created in code. Columns can be manipulated via
+ * the {@link setColumns Columns} property of the datagrid. For example,
+ * <code>
+ * $column=new TBoundColumn;
+ * $datagrid->Columns[]=$column;
+ * </code>
+ * </li>
+ * </ul>
+ * Note, automatically generated columns cannot be accessed via
+ * the {@link getColumns Columns} property.
+ *
+ * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
+ * is set to true, a column with nonempty {@link setSortExpression SortExpression}
+ * will have its header text displayed as a clickable link button.
+ * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
+ * event. You can respond to this event, sort the data source according
+ * to the event parameter, and then invoke {@link databind()} on the datagrid
+ * to show to end users the sorted data.
+ *
+ * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
+ * is set to true, a pager will be displayed on top and/or bottom of the table.
+ * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
+ * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
+ * event. You can respond to this event, specify the page to be displayed by
+ * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property,
+ * and then invoke {@link databind()} on the datagrid to show to end users
+ * a new page of data.
+ *
+ * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
+ * datasource. The number of pages {@link getPageCount PageCount} is calculated based
+ * the item number and the {@link setPageSize PageSize} property.
+ * The datagrid will manage which section of the data source to be displayed
+ * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
+ * The second approach calculates the page number based on the
+ * {@link setVirtualItemCount VirtualItemCount} property and
+ * the {@link setPageSize PageSize} property. The datagrid will always
+ * display from the beginning of the datasource up to the number of
+ * {@link setPageSize PageSize} data items. This approach is especially
+ * useful when the datasource may contain too many data items to be managed by
+ * the datagrid efficiently.
+ *
+ * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
+ * event, the event will be bubbled up to the datagrid control.
+ * If the event's command name is recognizable by the datagrid control,
+ * a corresponding item event will be raised. The following item events will be
+ * raised upon a specific command:
+ * - OnEditCommand, if CommandName=edit
+ * - OnCancelCommand, if CommandName=cancel
+ * - OnSelectCommand, if CommandName=select
+ * - OnDeleteCommand, if CommandName=delete
+ * - OnUpdateCommand, if CommandName=update
+ * - onPageIndexChanged, if CommandName=page
+ * - OnSortCommand, if CommandName=sort
+ * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
+ * the above specific command events.
+ *
+ * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
+ * every newly created datagrid item. You can respond to this event to customize
+ * the content or style of the newly created item.
+ *
+ * Note, the data bound to the datagrid are reset to null after databinding.
+ * There are several ways to access the data associated with a datagrid row:
+ * - Access the data in {@link onItemDataBound OnItemDataBound} event
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datagrid row and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the data in viewstate and get it back during postbacks.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGrid extends TBaseDataList implements INamingContainer
+{
+ /**
+ * datagrid item types
+ * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
+ */
+ const IT_HEADER='Header';
+ const IT_FOOTER='Footer';
+ const IT_ITEM='Item';
+ const IT_SEPARATOR='Separator';
+ const IT_ALTERNATINGITEM='AlternatingItem';
+ const IT_EDITITEM='EditItem';
+ const IT_SELECTEDITEM='SelectedItem';
+ const IT_PAGER='Pager';
+
+ /**
+ * Command name that TDataGrid understands.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+ const CMD_SORT='Sort';
+ const CMD_PAGE='Page';
+ const CMD_PAGE_NEXT='Next';
+ const CMD_PAGE_PREV='Previous';
+ const CMD_PAGE_FIRST='First';
+ const CMD_PAGE_LAST='Last';
+
+ /**
+ * @var TDataGridColumnCollection manually created column collection
+ */
+ private $_columns=null;
+ /**
+ * @var TDataGridColumnCollection automatically created column collection
+ */
+ private $_autoColumns=null;
+ /**
+ * @var TList all columns including both manually and automatically created columns
+ */
+ private $_allColumns=null;
+ /**
+ * @var TDataGridItemCollection datagrid item collection
+ */
+ private $_items=null;
+ /**
+ * @var TDataGridItem header item
+ */
+ private $_header=null;
+ /**
+ * @var TDataGridItem footer item
+ */
+ private $_footer=null;
+ /**
+ * @var TPagedDataSource paged data source object
+ */
+ private $_pagedDataSource=null;
+ private $_topPager=null;
+ private $_bottomPager=null;
+ /**
+ * @var ITemplate template used when empty data is bounded
+ */
+ private $_emptyTemplate=null;
+ /**
+ * @var boolean whether empty template is effective
+ */
+ private $_useEmptyTemplate=false;
+
+ /**
+ * @return string tag name (table) of the datagrid
+ */
+ protected function getTagName()
+ {
+ return 'table';
+ }
+
+ /**
+ * @return string Name of the class used in AutoGenerateColumns mode
+ */
+ protected function getAutoGenerateColumnName()
+ {
+ return 'TBoundColumn';
+ }
+
+ /**
+ * Adds objects parsed in template to datagrid.
+ * Datagrid columns are added into {@link getColumns Columns} collection.
+ * @param mixed object parsed in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TDataGridColumn)
+ $this->getColumns()->add($object);
+ else
+ parent::addParsedObject($object); // this is needed by EmptyTemplate
+ }
+
+ /**
+ * @return TDataGridColumnCollection manually specified datagrid columns
+ */
+ public function getColumns()
+ {
+ if(!$this->_columns)
+ $this->_columns=new TDataGridColumnCollection($this);
+ return $this->_columns;
+ }
+
+ /**
+ * @return TDataGridColumnCollection automatically generated datagrid columns
+ */
+ public function getAutoColumns()
+ {
+ if(!$this->_autoColumns)
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ return $this->_autoColumns;
+ }
+
+ /**
+ * @return TDataGridItemCollection datagrid item collection
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataGridItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by datagrid.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * @return string the URL of the background image for the datagrid
+ */
+ public function getBackImageUrl()
+ {
+ return $this->getStyle()->getBackImageUrl();
+ }
+
+ /**
+ * @param string the URL of the background image for the datagrid
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * @return TTableItemStyle the style for every item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TDataGridPagerStyle the style for pager
+ */
+ public function getPagerStyle()
+ {
+ if(($style=$this->getViewState('PagerStyle',null))===null)
+ {
+ $style=new TDataGridPagerStyle;
+ $this->setViewState('PagerStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for thead element, if any
+ * @since 3.1.1
+ */
+ public function getTableHeadStyle()
+ {
+ if(($style=$this->getViewState('TableHeadStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableHeadStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tbody element, if any
+ * @since 3.1.1
+ */
+ public function getTableBodyStyle()
+ {
+ if(($style=$this->getViewState('TableBodyStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableBodyStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style for tfoot element, if any
+ * @since 3.1.1
+ */
+ public function getTableFootStyle()
+ {
+ if(($style=$this->getViewState('TableFootStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('TableFootStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string caption for the datagrid
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string caption for the datagrid
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',$value,'');
+ }
+
+ /**
+ * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @param TTableCaptionAlign datagrid caption alignment. Valid values include
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @return TDataGridItem the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TDataGridItem the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
+ */
+ public function getTopPager()
+ {
+ return $this->_topPager;
+ }
+
+ /**
+ * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
+ */
+ public function getBottomPager()
+ {
+ return $this->_bottomPager;
+ }
+
+ /**
+ * @return TDataGridItem the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if($item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TDataGridItem the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return boolean whether sorting is enabled. Defaults to false.
+ */
+ public function getAllowSorting()
+ {
+ return $this->getViewState('AllowSorting',false);
+ }
+
+ /**
+ * @param boolean whether sorting is enabled
+ */
+ public function setAllowSorting($value)
+ {
+ $this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
+ */
+ public function getAutoGenerateColumns()
+ {
+ return $this->getViewState('AutoGenerateColumns',true);
+ }
+
+ /**
+ * @param boolean whether datagrid columns should be automatically generated
+ */
+ public function setAutoGenerateColumns($value)
+ {
+ $this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the header should be displayed. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether the header should be displayed
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be displayed. Defaults to false.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',false);
+ }
+
+ /**
+ * @param boolean whether the footer should be displayed
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datagrid
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datagrid
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * {@link TDataGridItem} child controls.
+ * If the event parameter is {@link TDataGridCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataGridCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ $this->setSelectedItemIndex($param->getItem()->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_SORT)===0)
+ {
+ $this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE)===0)
+ {
+ $p=$param->getCommandParameter();
+ if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
+ $pageIndex=$this->getCurrentPageIndex()-1;
+ else if(strcasecmp($p,self::CMD_PAGE_FIRST)===0)
+ $pageIndex=0;
+ else if(strcasecmp($p,self::CMD_PAGE_LAST)===0)
+ $pageIndex=$this->getPageCount()-1;
+ else
+ $pageIndex=TPropertyValue::ensureInteger($p)-1;
+ $this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises <b>OnCancelCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>cancel</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeleteCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>delete</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnEditCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>edit</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnSortCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>sort</b> command name.
+ * @param TDataGridSortCommandEventParameter event parameter
+ */
+ public function onSortCommand($param)
+ {
+ $this->raiseEvent('OnSortCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnUpdateCommand</b> event.
+ * This method is invoked when a button control raises <b>OnCommand</b> event
+ * with <b>update</b> command name.
+ * @param TDataGridCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked right after a datagrid item is created and before
+ * added to page hierarchy.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPagerCreated</b> event.
+ * This method is invoked right after a datagrid pager is created and before
+ * added to page hierarchy.
+ * @param TDataGridPagerEventParameter event parameter
+ */
+ public function onPagerCreated($param)
+ {
+ $this->raiseEvent('OnPagerCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked for each datagrid item after it performs
+ * databinding.
+ * @param TDataGridItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPageIndexChanged</b> event.
+ * This method is invoked when current page is changed.
+ * @param TDataGridPageChangedEventParameter event parameter
+ */
+ public function onPageIndexChanged($param)
+ {
+ $this->raiseEvent('OnPageIndexChanged',$this,$param);
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ if($this->_autoColumns)
+ {
+ $state=array();
+ foreach($this->_autoColumns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('AutoColumns',$state,array());
+ }
+ else
+ $this->clearViewState('AutoColumns');
+ if($this->_columns)
+ {
+ $state=array();
+ foreach($this->_columns as $column)
+ $state[]=$column->saveState();
+ $this->setViewState('Columns',$state,array());
+ }
+ else
+ $this->clearViewState('Columns');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getEnableViewState(true))
+ return;
+ if(!$this->getIsDataBound())
+ {
+ $state=$this->getViewState('AutoColumns',array());
+ if(!empty($state))
+ {
+ $this->_autoColumns=new TDataGridColumnCollection($this);
+ foreach($state as $st)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ $column->loadState($st);
+ $this->_autoColumns->add($column);
+ }
+ }
+ else
+ $this->_autoColumns=null;
+ $state=$this->getViewState('Columns',array());
+ if($this->_columns && $this->_columns->getCount()===count($state))
+ {
+ $i=0;
+ foreach($this->_columns as $column)
+ {
+ $column->loadState($state[$i]);
+ $i++;
+ }
+ }
+ $this->restoreGridFromViewState();
+ }
+ }
+
+ /**
+ * Clears up all items in the datagrid.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ $this->_topPager=null;
+ $this->_bottomPager=null;
+ $this->_useEmptyTemplate=false;
+ }
+
+ /**
+ * Restores datagrid content from viewstate.
+ */
+ protected function restoreGridFromViewState()
+ {
+ $this->reset();
+
+ $allowPaging=$this->getAllowPaging();
+
+ $itemCount=$this->getViewState('ItemCount',0);
+ $dsIndex=$this->getViewState('DataSourceIndex',0);
+
+ $columns=new TList($this->getColumns());
+ $columns->mergeWith($this->_autoColumns);
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ for($index=0;$index<$itemCount;++$index)
+ {
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+ }
+
+ /**
+ * Performs databinding to populate datagrid items from data source.
+ * This method is invoked by {@link dataBind()}.
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the bound data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
+ // get all columns
+ if($this->getAutoGenerateColumns())
+ {
+ $columns=new TList($this->getColumns());
+ $autoColumns=$this->createAutoColumns($data);
+ $columns->mergeWith($autoColumns);
+ }
+ else
+ $columns=$this->getColumns();
+ $this->_allColumns=$columns;
+
+ $items=$this->getItems();
+
+ $index=0;
+ $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
+ $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
+ $this->setViewState('DataSourceIndex',$dsIndex,0);
+ if($columns->getCount())
+ {
+ foreach($columns as $column)
+ $column->initialize();
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$row)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($row,$keyField));
+ else
+ $keys->add($key);
+ if($index===0)
+ {
+ if($allowPaging)
+ $this->_topPager=$this->createPager();
+ $this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
+ }
+ if($index===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($index===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else if($index % 2)
+ $itemType=TListItemType::AlternatingItem;
+ else
+ $itemType=TListItemType::Item;
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
+ $index++;
+ $dsIndex++;
+ }
+ if($index>0)
+ {
+ $this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
+ if($allowPaging)
+ $this->_bottomPager=$this->createPager();
+ }
+ }
+ $this->setViewState('ItemCount',$index,0);
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ $this->dataBindChildren();
+ }
+ }
+
+ /**
+ * Merges consecutive cells who have the same text.
+ * @since 3.1.1
+ */
+ private function groupCells()
+ {
+ if(($columns=$this->_allColumns)===null)
+ return;
+ $items=$this->getItems();
+ foreach($columns as $id=>$column)
+ {
+ if(!$column->getEnableCellGrouping())
+ continue;
+ $prevCell=null;
+ $prevCellText=null;
+ foreach($items as $item)
+ {
+ $itemType=$item->getItemType();
+ $cell=$item->getCells()->itemAt($id);
+ if(!$cell->getVisible())
+ continue;
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ if(($cellText=$this->getCellText($cell))==='')
+ {
+ $prevCell=null;
+ $prevCellText=null;
+ continue;
+ }
+ if($prevCell===null || $prevCellText!==$cellText)
+ {
+ $prevCell=$cell;
+ $prevCellText=$cellText;
+ }
+ else
+ {
+ if(($rowSpan=$prevCell->getRowSpan())===0)
+ $rowSpan=1;
+ $prevCell->setRowSpan($rowSpan+1);
+ $cell->setVisible(false);
+ }
+ }
+ }
+ }
+ }
+
+ private function getCellText($cell)
+ {
+ if(($data=$cell->getText())==='' && $cell->getHasControls())
+ {
+ $controls=$cell->getControls();
+ foreach($controls as $control)
+ {
+ if($control instanceof IDataRenderer)
+ return $control->getData();
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Creates a datagrid item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TDataGridItem created data list item
+ */
+ protected function createItem($itemIndex,$dataSourceIndex,$itemType)
+ {
+ return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
+ }
+
+ private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
+ {
+ $item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
+ $this->initializeItem($item,$columns);
+ $param=new TDataGridItemEventParameter($item);
+ if($dataBind)
+ {
+ $item->setDataItem($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ }
+ else
+ {
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ }
+ return $item;
+ }
+
+ /**
+ * Initializes a datagrid item and cells inside it
+ * @param TDataGrid datagrid item to be initialized
+ * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
+ */
+ protected function initializeItem($item,$columns)
+ {
+ $cells=$item->getCells();
+ $itemType=$item->getItemType();
+ $index=0;
+ foreach($columns as $column)
+ {
+ if($itemType===TListItemType::Header)
+ $cell=new TTableHeaderCell;
+ else
+ $cell=new TTableCell;
+ if(($id=$column->getID())!=='')
+ $item->registerObject($id,$cell);
+ $cells->add($cell);
+ $column->initializeCell($cell,$index,$itemType);
+ $index++;
+ }
+ }
+
+ protected function createPager()
+ {
+ $pager=new TDataGridPager($this);
+ $this->buildPager($pager);
+ $this->onPagerCreated(new TDataGridPagerEventParameter($pager));
+ $this->getControls()->add($pager);
+ return $pager;
+ }
+
+ /**
+ * Builds the pager content based on pager style.
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildPager($pager)
+ {
+ switch($this->getPagerStyle()->getMode())
+ {
+ case TDataGridPagerMode::NextPrev:
+ $this->buildNextPrevPager($pager);
+ break;
+ case TDataGridPagerMode::Numeric:
+ $this->buildNumericPager($pager);
+ break;
+ }
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param mixed the container pager instance of TActiveDatagridPager
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($pager,$buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TDataGridPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
+ }
+ else
+ {
+ $button=new TButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ return $button;
+ }
+
+ /**
+ * Builds a next-prev pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNextPrevPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $currentPageIndex=$this->getCurrentPageIndex();
+ if($currentPageIndex===0)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ $controls->add("\n");
+ }
+
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getPrevPageText(),'','');
+ $controls->add($label);
+ }
+ else
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
+ $controls->add($button);
+ }
+ $controls->add("\n");
+ if($currentPageIndex===$this->getPageCount()-1)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,$style->getNextPageText(),'','');
+ $controls->add($label);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $label=$this->createPagerButton($pager,$buttonType,false,$text,'','');
+ $controls->add($label);
+ }
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a numeric pager
+ * @param TDataGridPager the container for the pager
+ */
+ protected function buildNumericPager($pager)
+ {
+ $style=$this->getPagerStyle();
+ $buttonType=$style->getButtonType();
+ $controls=$pager->getControls();
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $maxButtonCount=$style->getPageButtonCount();
+ $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
+ $startPageIndex=1;
+ $endPageIndex=$buttonCount;
+ if($pageIndex>$endPageIndex)
+ {
+ $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
+ if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
+ $endPageIndex=$pageCount;
+ if($endPageIndex-$startPageIndex+1<$maxButtonCount)
+ {
+ if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
+ $startPageIndex=1;
+ }
+ }
+
+ if($startPageIndex>1)
+ {
+ if(($text=$style->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_FIRST);
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ for($i=$startPageIndex;$i<=$endPageIndex;++$i)
+ {
+ if($i===$pageIndex)
+ {
+ $label=$this->createPagerButton($pager,$buttonType,false,"$i",'','');
+ $controls->add($label);
+ }
+ else
+ {
+ $button=$this->createPagerButton($pager,$buttonType,true,"$i",self::CMD_PAGE,"$i");
+ $controls->add($button);
+ }
+ if($i<$endPageIndex)
+ $controls->add("\n");
+ }
+
+ if($pageCount>$endPageIndex)
+ {
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($pager,$buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
+ $controls->add($button);
+ if(($text=$style->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($pager,$buttonType,true,$text,self::CMD_PAGE,self::CMD_PAGE_LAST);
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Automatically generates datagrid columns based on datasource schema
+ * @param Traversable data source bound to the datagrid
+ * @return TDataGridColumnCollection
+ */
+ protected function createAutoColumns($dataSource)
+ {
+ if(!$dataSource)
+ return null;
+ $autoColumns=$this->getAutoColumns();
+ $autoColumns->clear();
+ foreach($dataSource as $row)
+ {
+ foreach($row as $key=>$value)
+ {
+ $column=new $this->AutoGenerateColumnName;
+ if(is_string($key))
+ {
+ $column->setHeaderText($key);
+ $column->setDataField($key);
+ $column->setSortExpression($key);
+ $autoColumns->add($column);
+ }
+ else
+ {
+ $column->setHeaderText(TListItemType::Item);
+ $column->setDataField($key);
+ $column->setSortExpression(TListItemType::Item);
+ $autoColumns->add($column);
+ }
+ }
+ break;
+ }
+ return $autoColumns;
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ $headerStyle=$this->getViewState('HeaderStyle',null);
+ $footerStyle=$this->getViewState('FooterStyle',null);
+ $pagerStyle=$this->getViewState('PagerStyle',null);
+ $separatorStyle=$this->getViewState('SeparatorStyle',null);
+
+ foreach($this->getControls() as $index=>$item)
+ {
+ if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
+ continue;
+ $itemType=$item->getItemType();
+ switch($itemType)
+ {
+ case TListItemType::Header:
+ if($headerStyle)
+ $item->getStyle()->mergeWith($headerStyle);
+ if(!$this->getShowHeader())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Footer:
+ if($footerStyle)
+ $item->getStyle()->mergeWith($footerStyle);
+ if(!$this->getShowFooter())
+ $item->setVisible(false);
+ break;
+ case TListItemType::Separator:
+ if($separatorStyle)
+ $item->getStyle()->mergeWith($separatorStyle);
+ break;
+ case TListItemType::Item:
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ break;
+ case TListItemType::AlternatingItem:
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ break;
+ case TListItemType::SelectedItem:
+ if($selectedItemStyle)
+ $item->getStyle()->mergeWith($selectedItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::EditItem:
+ if($editItemStyle)
+ $item->getStyle()->mergeWith($editItemStyle);
+ if($index % 2==1)
+ {
+ if($itemStyle)
+ $item->getStyle()->mergeWith($itemStyle);
+ }
+ else
+ {
+ if($alternatingItemStyle)
+ $item->getStyle()->mergeWith($alternatingItemStyle);
+ }
+ break;
+ case TListItemType::Pager:
+ if($pagerStyle)
+ {
+ $item->getStyle()->mergeWith($pagerStyle);
+ if($index===0)
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ else
+ {
+ if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
+ $item->setVisible(false);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if($this->_columns && $itemType!==TListItemType::Pager)
+ {
+ $n=$this->_columns->getCount();
+ $cells=$item->getCells();
+ for($i=0;$i<$n;++$i)
+ {
+ $cell=$cells->itemAt($i);
+ $column=$this->_columns->itemAt($i);
+ if(!$column->getVisible())
+ $cell->setVisible(false);
+ else
+ {
+ if($itemType===TListItemType::Header)
+ $style=$column->getHeaderStyle(false);
+ else if($itemType===TListItemType::Footer)
+ $style=$column->getFooterStyle(false);
+ else
+ $style=$column->getItemStyle(false);
+ if($style!==null)
+ $cell->getStyle()->mergeWith($style);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the openning tag for the datagrid control which will render table caption if present.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($caption=$this->getCaption())!=='')
+ {
+ if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
+ $writer->addAttribute('align',strtolower($align));
+ $writer->renderBeginTag('caption');
+ $writer->write($caption);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the datagrid.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ $this->groupCells();
+ if($this->_useEmptyTemplate)
+ {
+ $control=new TWebControl;
+ $control->setID($this->getClientID());
+ $control->copyBaseAttributes($this);
+ if($this->getHasStyle())
+ $control->getStyle()->copyFrom($this->getStyle());
+ $control->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $control->renderEndTag($writer);
+ }
+ else if($this->getViewState('ItemCount',0)>0)
+ {
+ $this->applyItemStyles();
+ if($this->_topPager)
+ {
+ $this->_topPager->renderControl($writer);
+ $writer->writeLine();
+ }
+ $this->renderTable($writer);
+ if($this->_bottomPager)
+ {
+ $writer->writeLine();
+ $this->_bottomPager->renderControl($writer);
+ }
+ }
+ }
+ }
+
+ /**
+ * Renders the tabular data.
+ * @param THtmlWriter writer
+ */
+ protected function renderTable($writer)
+ {
+ $this->renderBeginTag($writer);
+ if($this->_header && $this->_header->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableHeadStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('thead');
+ $this->_header->render($writer);
+ $writer->renderEndTag();
+ }
+ $writer->writeLine();
+ if($style=$this->getViewState('TableBodyStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tbody');
+ foreach($this->getItems() as $item)
+ $item->renderControl($writer);
+ $writer->renderEndTag();
+
+ if($this->_footer && $this->_footer->getVisible())
+ {
+ $writer->writeLine();
+ if($style=$this->getViewState('TableFootStyle',null))
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('tfoot');
+ $this->_footer->render($writer);
+ $writer->renderEndTag();
+ }
+
+ $writer->writeLine();
+ $this->renderEndTag($writer);
+ }
+}
+
+/**
+ * TDataGridItemEventParameter class
+ *
+ * TDataGridItemEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridItem control responsible for the event.
+ * @var TDataGridItem
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item related with the corresponding event
+ */
+ public function __construct(TDataGridItem $item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TDataGridItem datagrid item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataGridPagerEventParameter class
+ *
+ * TDataGridPagerEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
+ * The {@link getPager Pager} property indicates the datagrid pager related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerEventParameter extends TEventParameter
+{
+ /**
+ * The TDataGridPager control responsible for the event.
+ * @var TDataGridPager
+ */
+ protected $_pager=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function __construct(TDataGridPager $pager)
+ {
+ $this->_pager=$pager;
+ }
+
+ /**
+ * @return TDataGridPager datagrid pager related with the corresponding event
+ */
+ public function getPager()
+ {
+ return $this->_pager;
+ }
+}
+
+/**
+ * TDataGridCommandEventParameter class
+ *
+ * TDataGridCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getItem Item} property indicates the datagrid item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>Command</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TDataGridItem datagrid item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TDataGridItem the TDataGridItem control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>Command</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataGridSortCommandEventParameter class
+ *
+ * TDataGridSortCommandEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
+ * gives the sort expression carried with the sort command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridSortCommandEventParameter extends TEventParameter
+{
+ /**
+ * @var string sort expression
+ */
+ private $_sortExpression='';
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param TDataGridCommandEventParameter command event parameter
+ */
+ public function __construct($source,TDataGridCommandEventParameter $param)
+ {
+ $this->_source=$source;
+ $this->_sortExpression=$param->getCommandParameter();
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return string sort expression
+ */
+ public function getSortExpression()
+ {
+ return $this->_sortExpression;
+ }
+}
+
+/**
+ * TDataGridPageChangedEventParameter class
+ *
+ * TDataGridPageChangedEventParameter encapsulates the parameter data for
+ * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
+ * returns the new page index carried with the page command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPageChangedEventParameter extends TEventParameter
+{
+ /**
+ * @var integer new page index
+ */
+ private $_newIndex;
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param integer new page index
+ */
+ public function __construct($source,$newPageIndex)
+ {
+ $this->_source=$source;
+ $this->_newIndex=$newPageIndex;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return integer new page index
+ */
+ public function getNewPageIndex()
+ {
+ return $this->_newIndex;
+ }
+}
+
+/**
+ * TDataGridItem class
+ *
+ * A TDataGridItem control represents an item in the {@link TDataGrid} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
+ * gives the index of the item from the bound data source.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItem extends TTableRow implements INamingContainer
+{
+ /**
+ * @var integer index of the data item in the Items collection of datagrid
+ */
+ private $_itemIndex='';
+ /**
+ * @var integer index of the item from the bound data source
+ */
+ private $_dataSourceIndex=0;
+ /**
+ * type of the TDataGridItem
+ * @var string
+ */
+ private $_itemType='';
+ /**
+ * value of the data item
+ * @var mixed
+ */
+ private $_data=null;
+
+ /**
+ * Constructor.
+ * @param integer zero-based index of the item in the item collection of datagrid
+ * @param TListItemType item type
+ */
+ public function __construct($itemIndex,$dataSourceIndex,$itemType)
+ {
+ $this->_itemIndex=$itemIndex;
+ $this->_dataSourceIndex=$dataSourceIndex;
+ $this->setItemType($itemType);
+ if($itemType===TListItemType::Header)
+ $this->setTableSection(TTableRowSection::Header);
+ else if($itemType===TListItemType::Footer)
+ $this->setTableSection(TTableRowSection::Footer);
+ }
+
+ /**
+ * @return TListItemType item type.
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datagrid
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * @return integer the index of the datagrid item from the bound data source
+ */
+ public function getDataSourceIndex()
+ {
+ return $this->_dataSourceIndex;
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+
+/**
+ * TDataGridPager class.
+ *
+ * TDataGridPager represents a datagrid pager.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPager extends TPanel implements INamingContainer
+{
+ private $_dataGrid;
+
+ /**
+ * Constructor.
+ * @param TDataGrid datagrid object
+ */
+ public function __construct($dataGrid)
+ {
+ $this->_dataGrid=$dataGrid;
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @return TDataGrid the datagrid owning this pager
+ */
+ public function getDataGrid()
+ {
+ return $this->_dataGrid;
+ }
+
+ /**
+ * @return string item type.
+ */
+ public function getItemType()
+ {
+ return TListItemType::Pager;
+ }
+}
+
+
+/**
+ * TDataGridItemCollection class.
+ *
+ * TDataGridItemCollection represents a collection of data grid items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridItem.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridItem)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
+ }
+}
+
+/**
+ * TDataGridColumnCollection class.
+ *
+ * TDataGridColumnCollection represents a collection of data grid columns.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridColumnCollection extends TList
+{
+ /**
+ * the control that owns this collection.
+ * @var TControl
+ */
+ private $_o;
+
+ /**
+ * Constructor.
+ * @param TDataGrid the control that owns this collection.
+ */
+ public function __construct(TDataGrid $owner)
+ {
+ $this->_o=$owner;
+ }
+
+ /**
+ * @return TDataGrid the control that owns this collection.
+ */
+ protected function getOwner()
+ {
+ return $this->_o;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TDataGridColumn.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TDataGridColumn)
+ {
+ $item->setOwner($this->_o);
+ parent::insertAt($index,$item);
+ }
+ else
+ throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
+ }
+}
+
+/**
+ * TDataGridPagerMode class.
+ * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
+ *
+ * The following enumerable values are defined:
+ * - NextPrev: pager buttons are displayed as next and previous pages
+ * - Numeric: pager buttons are displayed as numeric page numbers
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerMode extends TEnumerable
+{
+ const NextPrev='NextPrev';
+ const Numeric='Numeric';
+}
+
+
+/**
+ * TDataGridPagerButtonType class.
+ * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form submit buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerButtonType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+}
+
+
+/**
+ * TDataGridPagerPosition class.
+ * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
+ *
+ * The following enumerable values are defined:
+ * - Bottom: pager appears only at the bottom of the data grid.
+ * - Top: pager appears only at the top of the data grid.
+ * - TopAndBottom: pager appears on both top and bottom of the data grid.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDataGridPagerPosition extends TEnumerable
+{
+ const Bottom='Bottom';
+ const Top='Top';
+ const TopAndBottom='TopAndBottom';
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php
index d37fbc40..4794fbf8 100644
--- a/framework/Web/UI/WebControls/TDataGridColumn.php
+++ b/framework/Web/UI/WebControls/TDataGridColumn.php
@@ -1,567 +1,567 @@
-<?php
-/**
- * TDataGridColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Util.TDataFieldAccessor');
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridColumn class
- *
- * TDataGridColumn serves as the base class for the different column types of
- * the {@link TDataGrid} control.
- * TDataGridColumn defines the properties and methods that are common among
- * all datagrid column types. In particular, it initializes header and footer
- * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
- * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
- * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
- * will be displayed instead in the header cell.
- * The {@link getItemStyle ItemStyle} is applied to cells that belong to
- * non-header and -footer datagrid items.
- *
- * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
- * is not empty, the header cell will display a button (linkbutton or imagebutton)
- * that will bubble the sort command event to the datagrid.
- *
- * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
- * and {@link setFooterRenderer FooterRenderer} which can be used to specify
- * the layout of header and footer column cells.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
- * If a column has this property set true, consecutive cells having the same content in this
- * column will be grouped into one cell.
- * Note, there are some limitations to cell grouping. We determine the cell content according to
- * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
- * some child controls, we will pick up the first control who implements {@link IDataRenderer}
- * and obtain its {@link IDataRenderer::getData Data} property.
- *
- * The following datagrid column types are provided by the framework currently,
- * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
- * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
- * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
- * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
- * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
- * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
- * - {@link TTemplateColumn}, displaying content based on templates.
- *
- * To create your own column class, simply override {@link initializeCell()} method,
- * which is the major logic for managing the data and presentation of cells in the column.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataGridColumn extends TApplicationComponent
-{
- private $_id='';
- private $_owner=null;
- private $_viewState=array();
-
- /**
- * @return string the ID of the column.
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * Sets the ID of the column.
- * By explicitly specifying the column ID, one can access the column
- * by $templateControl->ColumnID.
- * @param string the ID of the column.
- * @throws TInvalidDataValueException if the ID is of bad format
- */
- public function setID($value)
- {
- if(!preg_match(TControl::ID_FORMAT,$value))
- throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
- $this->_id=$value;
- }
-
- /**
- * @return string the text to be displayed in the header of this column
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * @param string text to be displayed in the header of this column
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',$value,'');
- }
-
- /**
- * @return string the url of the image to be displayed in header
- */
- public function getHeaderImageUrl()
- {
- return $this->getViewState('HeaderImageUrl','');
- }
-
- /**
- * @param string the url of the image to be displayed in header
- */
- public function setHeaderImageUrl($value)
- {
- $this->setViewState('HeaderImageUrl',$value,'');
- }
-
- /**
- * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the column header cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column header cell.
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle($createStyle=true)
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the text to be displayed in the footer of this column
- */
- public function getFooterText()
- {
- return $this->getViewState('FooterText','');
- }
-
- /**
- * @param string text to be displayed in the footer of this column
- */
- public function setFooterText($value)
- {
- $this->setViewState('FooterText',$value,'');
- }
-
- /**
- * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the column footer cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the column footer cell.
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the {@link getFooterText FooterText}.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle($createStyle=true)
- {
- if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @param boolean whether to create a style if previously not existing
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle($createStyle=true)
- {
- if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return string the name of the field or expression for sorting
- */
- public function getSortExpression()
- {
- return $this->getViewState('SortExpression','');
- }
-
- /**
- * @param string the name of the field or expression for sorting
- */
- public function setSortExpression($value)
- {
- $this->setViewState('SortExpression',$value,'');
- }
-
- /**
- * @return boolean whether cells having the same content should be grouped together. Defaults to false.
- * @since 3.1.1
- */
- public function getEnableCellGrouping()
- {
- return $this->getViewState('EnableCellGrouping',false);
- }
-
- /**
- * @param boolean whether cells having the same content should be grouped together.
- * @since 3.1.1
- */
- public function setEnableCellGrouping($value)
- {
- $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the column is visible. Defaults to true.
- */
- public function getVisible($checkParents=true)
- {
- return $this->getViewState('Visible',true);
- }
-
- /**
- * @param boolean whether the column is visible
- */
- public function setVisible($value)
- {
- $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Returns a viewstate value.
- *
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- protected function getViewState($key,$defaultValue=null)
- {
- return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- protected function setViewState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_viewState[$key]);
- else
- $this->_viewState[$key]=$value;
- }
-
- /**
- * Loads persistent state values.
- * @param mixed state values
- */
- public function loadState($state)
- {
- $this->_viewState=$state;
- }
-
- /**
- * Saves persistent state values.
- * @return mixed values to be saved
- */
- public function saveState()
- {
- return $this->_viewState;
- }
-
- /**
- * @return TDataGrid datagrid that owns this column
- */
- public function getOwner()
- {
- return $this->_owner;
- }
-
- /**
- * @param TDataGrid datagrid object that owns this column
- */
- public function setOwner(TDataGrid $value)
- {
- $this->_owner=$value;
- }
-
- /**
- * Initializes the column.
- * This method is invoked by {@link TDataGrid} when the column
- * is about to be used to initialize datagrid items.
- * Derived classes may override this method to do additional initialization.
- */
- public function initialize()
- {
- }
-
- /**
- * Fetches the value of the data at the specified field.
- * If the data is an array, the field is used as an array key.
- * If the data is an of {@link TMap}, {@link TList} or their derived class,
- * the field is used as a key value.
- * If the data is a component, the field is used as the name of a property.
- * @param mixed data containing the field of value
- * @param string the data field
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data or the field is invalid.
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-
-
- /**
- * Initializes the specified cell to its initial values.
- * The default implementation sets the content of header and footer cells.
- * If sorting is enabled by the grid and sort expression is specified in the column,
- * the header cell will show a link/image button. Otherwise, the header/footer cell
- * will only show static text/image.
- * This method can be overriden to provide customized intialization to column cells.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Header)
- $this->initializeHeaderCell($cell,$columnIndex);
- else if($itemType===TListItemType::Footer)
- $this->initializeFooterCell($cell,$columnIndex);
- }
-
- /**
- * Returns a value indicating whether this column allows sorting.
- * The column allows sorting only when {@link getSortExpression SortExpression}
- * is not empty and the datagrid allows sorting.
- * @return boolean whether this column allows sorting
- */
- public function getAllowSorting()
- {
- return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
- }
-
- /**
- * Initializes the header cell.
- *
- * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
- * instantiate the header cell. If that is not available, it will populate
- * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
- * and {@link getHeaderText HeaderText} property values.
- *
- * If the column allows sorting, image or text will be created as
- * a button which issues <b>Sort</b> command upon user click.
- *
- * @param TTableCell the cell to be initialized
- * @param integer the index to the Columns property that the cell resides in.
- */
- protected function initializeHeaderCell($cell,$columnIndex)
- {
- $text=$this->getHeaderText();
-
- if(($classPath=$this->getHeaderRenderer())!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IDataRenderer)
- {
- if($control instanceof IItemDataRenderer)
- {
- $item=$cell->getParent();
- $control->setItemIndex($item->getItemIndex());
- $control->setItemType($item->getItemType());
- }
- $control->setData($text);
- }
- }
- else if($this->getAllowSorting())
- {
- $sortExpression=$this->getSortExpression();
- if(($url=$this->getHeaderImageUrl())!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- $button->setImageUrl($url);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- if($text!=='')
- $button->setAlternateText($text);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else if($text!=='')
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- $button->setText($text);
- $button->setCommandName(TDataGrid::CMD_SORT);
- $button->setCommandParameter($sortExpression);
- $button->setCausesValidation(false);
- $cell->getControls()->add($button);
- }
- else
- $cell->setText('&nbsp;');
- }
- 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('&nbsp;');
- }
- }
-
- /**
- * 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('&nbsp;');
- }
-
- /**
- * Formats the text value according to a format string.
- * If the format string is empty, the original value is converted into
- * a string and returned.
- * If the format string starts with '#', the string is treated as a PHP expression
- * within which the token '{0}' is translated with the data value to be formated.
- * Otherwise, the format string and the data value are passed
- * as the first and second parameters in {@link sprintf}.
- * @param string format string
- * @param mixed the data to be formatted
- * @return string the formatted result
- */
- protected function formatDataValue($formatString,$value)
- {
- if($formatString==='')
- return TPropertyValue::ensureString($value);
- else if($formatString[0]==='#')
- {
- $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
- try
- {
- if(eval("\$result=$expression;")===false)
- throw new Exception('');
- return $result;
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
- }
- }
- else
- return sprintf($formatString,$value);
- }
-}
-
-
-/**
- * TButtonColumnType class.
- * TButtonColumnType defines the enumerable type for the possible types of buttons
- * that can be used in a {@link TButtonColumn}.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form buttons
- * - ImageButton: image buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TButtonColumnType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
- const ImageButton='ImageButton';
-}
-
+<?php
+/**
+ * TDataGridColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Util.TDataFieldAccessor');
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridColumn class
+ *
+ * TDataGridColumn serves as the base class for the different column types of
+ * the {@link TDataGrid} control.
+ * TDataGridColumn defines the properties and methods that are common among
+ * all datagrid column types. In particular, it initializes header and footer
+ * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
+ * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
+ * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
+ * will be displayed instead in the header cell.
+ * The {@link getItemStyle ItemStyle} is applied to cells that belong to
+ * non-header and -footer datagrid items.
+ *
+ * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
+ * is not empty, the header cell will display a button (linkbutton or imagebutton)
+ * that will bubble the sort command event to the datagrid.
+ *
+ * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
+ * and {@link setFooterRenderer FooterRenderer} which can be used to specify
+ * the layout of header and footer column cells.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
+ * If a column has this property set true, consecutive cells having the same content in this
+ * column will be grouped into one cell.
+ * Note, there are some limitations to cell grouping. We determine the cell content according to
+ * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
+ * some child controls, we will pick up the first control who implements {@link IDataRenderer}
+ * and obtain its {@link IDataRenderer::getData Data} property.
+ *
+ * The following datagrid column types are provided by the framework currently,
+ * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
+ * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
+ * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
+ * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
+ * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
+ * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
+ * - {@link TTemplateColumn}, displaying content based on templates.
+ *
+ * To create your own column class, simply override {@link initializeCell()} method,
+ * which is the major logic for managing the data and presentation of cells in the column.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataGridColumn extends TApplicationComponent
+{
+ private $_id='';
+ private $_owner=null;
+ private $_viewState=array();
+
+ /**
+ * @return string the ID of the column.
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Sets the ID of the column.
+ * By explicitly specifying the column ID, one can access the column
+ * by $templateControl->ColumnID.
+ * @param string the ID of the column.
+ * @throws TInvalidDataValueException if the ID is of bad format
+ */
+ public function setID($value)
+ {
+ if(!preg_match(TControl::ID_FORMAT,$value))
+ throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string the text to be displayed in the header of this column
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * @param string text to be displayed in the header of this column
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',$value,'');
+ }
+
+ /**
+ * @return string the url of the image to be displayed in header
+ */
+ public function getHeaderImageUrl()
+ {
+ return $this->getViewState('HeaderImageUrl','');
+ }
+
+ /**
+ * @param string the url of the image to be displayed in header
+ */
+ public function setHeaderImageUrl($value)
+ {
+ $this->setViewState('HeaderImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the column header cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column header cell.
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the text to be displayed in the footer of this column
+ */
+ public function getFooterText()
+ {
+ return $this->getViewState('FooterText','');
+ }
+
+ /**
+ * @param string text to be displayed in the footer of this column
+ */
+ public function setFooterText($value)
+ {
+ $this->setViewState('FooterText',$value,'');
+ }
+
+ /**
+ * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the column footer cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the column footer cell.
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the {@link getFooterText FooterText}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @param boolean whether to create a style if previously not existing
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle($createStyle=true)
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return string the name of the field or expression for sorting
+ */
+ public function getSortExpression()
+ {
+ return $this->getViewState('SortExpression','');
+ }
+
+ /**
+ * @param string the name of the field or expression for sorting
+ */
+ public function setSortExpression($value)
+ {
+ $this->setViewState('SortExpression',$value,'');
+ }
+
+ /**
+ * @return boolean whether cells having the same content should be grouped together. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getEnableCellGrouping()
+ {
+ return $this->getViewState('EnableCellGrouping',false);
+ }
+
+ /**
+ * @param boolean whether cells having the same content should be grouped together.
+ * @since 3.1.1
+ */
+ public function setEnableCellGrouping($value)
+ {
+ $this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the column is visible. Defaults to true.
+ */
+ public function getVisible($checkParents=true)
+ {
+ return $this->getViewState('Visible',true);
+ }
+
+ /**
+ * @param boolean whether the column is visible
+ */
+ public function setVisible($value)
+ {
+ $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Returns a viewstate value.
+ *
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ protected function getViewState($key,$defaultValue=null)
+ {
+ return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ protected function setViewState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_viewState[$key]);
+ else
+ $this->_viewState[$key]=$value;
+ }
+
+ /**
+ * Loads persistent state values.
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ $this->_viewState=$state;
+ }
+
+ /**
+ * Saves persistent state values.
+ * @return mixed values to be saved
+ */
+ public function saveState()
+ {
+ return $this->_viewState;
+ }
+
+ /**
+ * @return TDataGrid datagrid that owns this column
+ */
+ public function getOwner()
+ {
+ return $this->_owner;
+ }
+
+ /**
+ * @param TDataGrid datagrid object that owns this column
+ */
+ public function setOwner(TDataGrid $value)
+ {
+ $this->_owner=$value;
+ }
+
+ /**
+ * Initializes the column.
+ * This method is invoked by {@link TDataGrid} when the column
+ * is about to be used to initialize datagrid items.
+ * Derived classes may override this method to do additional initialization.
+ */
+ public function initialize()
+ {
+ }
+
+ /**
+ * Fetches the value of the data at the specified field.
+ * If the data is an array, the field is used as an array key.
+ * If the data is an of {@link TMap}, {@link TList} or their derived class,
+ * the field is used as a key value.
+ * If the data is a component, the field is used as the name of a property.
+ * @param mixed data containing the field of value
+ * @param string the data field
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data or the field is invalid.
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * The default implementation sets the content of header and footer cells.
+ * If sorting is enabled by the grid and sort expression is specified in the column,
+ * the header cell will show a link/image button. Otherwise, the header/footer cell
+ * will only show static text/image.
+ * This method can be overriden to provide customized intialization to column cells.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Header)
+ $this->initializeHeaderCell($cell,$columnIndex);
+ else if($itemType===TListItemType::Footer)
+ $this->initializeFooterCell($cell,$columnIndex);
+ }
+
+ /**
+ * Returns a value indicating whether this column allows sorting.
+ * The column allows sorting only when {@link getSortExpression SortExpression}
+ * is not empty and the datagrid allows sorting.
+ * @return boolean whether this column allows sorting
+ */
+ public function getAllowSorting()
+ {
+ return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
+ }
+
+ /**
+ * Initializes the header cell.
+ *
+ * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
+ * instantiate the header cell. If that is not available, it will populate
+ * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
+ * and {@link getHeaderText HeaderText} property values.
+ *
+ * If the column allows sorting, image or text will be created as
+ * a button which issues <b>Sort</b> command upon user click.
+ *
+ * @param TTableCell the cell to be initialized
+ * @param integer the index to the Columns property that the cell resides in.
+ */
+ protected function initializeHeaderCell($cell,$columnIndex)
+ {
+ $text=$this->getHeaderText();
+
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IDataRenderer)
+ {
+ if($control instanceof IItemDataRenderer)
+ {
+ $item=$cell->getParent();
+ $control->setItemIndex($item->getItemIndex());
+ $control->setItemType($item->getItemType());
+ }
+ $control->setData($text);
+ }
+ }
+ else if($this->getAllowSorting())
+ {
+ $sortExpression=$this->getSortExpression();
+ if(($url=$this->getHeaderImageUrl())!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ $button->setImageUrl($url);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ if($text!=='')
+ $button->setAlternateText($text);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else if($text!=='')
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ $button->setText($text);
+ $button->setCommandName(TDataGrid::CMD_SORT);
+ $button->setCommandParameter($sortExpression);
+ $button->setCausesValidation(false);
+ $cell->getControls()->add($button);
+ }
+ else
+ $cell->setText('&nbsp;');
+ }
+ 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('&nbsp;');
+ }
+ }
+
+ /**
+ * 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('&nbsp;');
+ }
+
+ /**
+ * Formats the text value according to a format string.
+ * If the format string is empty, the original value is converted into
+ * a string and returned.
+ * If the format string starts with '#', the string is treated as a PHP expression
+ * within which the token '{0}' is translated with the data value to be formated.
+ * Otherwise, the format string and the data value are passed
+ * as the first and second parameters in {@link sprintf}.
+ * @param string format string
+ * @param mixed the data to be formatted
+ * @return string the formatted result
+ */
+ protected function formatDataValue($formatString,$value)
+ {
+ if($formatString==='')
+ return TPropertyValue::ensureString($value);
+ else if($formatString[0]==='#')
+ {
+ $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
+ try
+ {
+ if(eval("\$result=$expression;")===false)
+ throw new Exception('');
+ return $result;
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
+ }
+ }
+ else
+ return sprintf($formatString,$value);
+ }
+}
+
+
+/**
+ * TButtonColumnType class.
+ * TButtonColumnType defines the enumerable type for the possible types of buttons
+ * that can be used in a {@link TButtonColumn}.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form buttons
+ * - ImageButton: image buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TButtonColumnType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+ const ImageButton='ImageButton';
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridItemRenderer.php b/framework/Web/UI/WebControls/TDataGridItemRenderer.php
index 0e30a062..dbbbec11 100644
--- a/framework/Web/UI/WebControls/TDataGridItemRenderer.php
+++ b/framework/Web/UI/WebControls/TDataGridItemRenderer.php
@@ -1,30 +1,30 @@
-<?php
-/**
- * TDataGridItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataGridItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataGridItemRenderer class
- *
- * TDataGridItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataGrid}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataGridItemRenderer extends TItemDataRenderer
-{
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataGridItemRenderer class
+ *
+ * TDataGridItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataGrid}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataGridItemRenderer extends TItemDataRenderer
+{
+}
+
diff --git a/framework/Web/UI/WebControls/TDataGridPagerStyle.php b/framework/Web/UI/WebControls/TDataGridPagerStyle.php
index 12346c06..2464291a 100644
--- a/framework/Web/UI/WebControls/TDataGridPagerStyle.php
+++ b/framework/Web/UI/WebControls/TDataGridPagerStyle.php
@@ -1,255 +1,255 @@
-<?php
-/**
- * TDataGridPagerStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGrid');
-
-/**
- * TDataGridPagerStyle class.
- *
- * TDataGridPagerStyle specifies the styles available for a datagrid pager.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataGridPagerStyle extends TPanelStyle
-{
- private $_mode=null;
- private $_nextText=null;
- private $_prevText=null;
- private $_firstText=null;
- private $_lastText=null;
- private $_buttonCount=null;
- private $_position=null;
- private $_visible=null;
- private $_buttonType=null;
-
- /**
- * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
- */
- public function getMode()
- {
- return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
- }
-
- /**
- * @param TDataGridPagerMode pager mode.
- */
- public function setMode($value)
- {
- $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
- }
-
- /**
- * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
- }
-
- /**
- * @param TDataGridPagerButtonType the type of command button
- */
- public function setButtonType($value)
- {
- $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
- }
-
- /**
- * @return string text for the next page button. Defaults to '>'.
- */
- public function getNextPageText()
- {
- return $this->_nextText===null?'>':$this->_nextText;
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setNextPageText($value)
- {
- $this->_nextText=$value;
- }
-
- /**
- * @return string text for the previous page button. Defaults to '<'.
- */
- public function getPrevPageText()
- {
- return $this->_prevText===null?'<':$this->_prevText;
- }
-
- /**
- * @param string text for the previous page button.
- */
- public function setPrevPageText($value)
- {
- $this->_prevText=$value;
- }
-
- /**
- * @return string text for the first page button. Defaults to '<<'.
- */
- public function getFirstPageText()
- {
- return $this->_firstText===null?'<<':$this->_firstText;
- }
-
- /**
- * @param string text for the first page button.
- */
- public function setFirstPageText($value)
- {
- $this->_firstText=$value;
- }
-
- /**
- * @return string text for the last page button. Defaults to '>>'.
- */
- public function getLastPageText()
- {
- return $this->_lastText===null?'>>':$this->_lastText;
- }
-
- /**
- * @param string text for the last page button.
- */
- public function setLastPageText($value)
- {
- $this->_lastText=$value;
- }
-
- /**
- * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
- */
- public function getPageButtonCount()
- {
- return $this->_buttonCount===null?10:$this->_buttonCount;
- }
-
- /**
- * @param integer maximum number of pager buttons to be displayed
- * @throws TInvalidDataValueException if the value is less than 1.
- */
- public function setPageButtonCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
- $this->_buttonCount=$value;
- }
-
- /**
- * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
- */
- public function getPosition()
- {
- return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
- }
-
- /**
- * @param TDataGridPagerPosition where the pager is to be displayed.
- */
- public function setPosition($value)
- {
- $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
- }
-
- /**
- * @return boolean whether the pager is visible. Defaults to true.
- */
- public function getVisible()
- {
- return $this->_visible===null?true:$this->_visible;
- }
-
- /**
- * @param boolean whether the pager is visible.
- */
- public function setVisible($value)
- {
- $this->_visible=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Resets the style to the original empty state.
- */
- public function reset()
- {
- parent::reset();
- $this->_visible=null;
- $this->_position=null;
- $this->_buttonCount=null;
- $this->_prevText=null;
- $this->_nextText=null;
- $this->_mode=null;
- $this->_buttonType=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($style->_visible!==null)
- $this->_visible=$style->_visible;
- if($style->_position!==null)
- $this->_position=$style->_position;
- if($style->_buttonCount!==null)
- $this->_buttonCount=$style->_buttonCount;
- if($style->_prevText!==null)
- $this->_prevText=$style->_prevText;
- if($style->_nextText!==null)
- $this->_nextText=$style->_nextText;
- if($style->_mode!==null)
- $this->_mode=$style->_mode;
- if($style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TDataGridPagerStyle)
- {
- if($this->_visible===null)
- $this->_visible=$style->_visible;
- if($this->_position===null)
- $this->_position=$style->_position;
- if($this->_buttonCount===null)
- $this->_buttonCount=$style->_buttonCount;
- if($this->_prevText===null)
- $this->_prevText=$style->_prevText;
- if($this->_nextText===null)
- $this->_nextText=$style->_nextText;
- if($this->_mode===null)
- $this->_mode=$style->_mode;
- if($this->_buttonType===null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-}
-
+<?php
+/**
+ * TDataGridPagerStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGrid');
+
+/**
+ * TDataGridPagerStyle class.
+ *
+ * TDataGridPagerStyle specifies the styles available for a datagrid pager.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataGridPagerStyle extends TPanelStyle
+{
+ private $_mode=null;
+ private $_nextText=null;
+ private $_prevText=null;
+ private $_firstText=null;
+ private $_lastText=null;
+ private $_buttonCount=null;
+ private $_position=null;
+ private $_visible=null;
+ private $_buttonType=null;
+
+ /**
+ * @return TDataGridPagerMode pager mode. Defaults to TDataGridPagerMode::NextPrev.
+ */
+ public function getMode()
+ {
+ return $this->_mode===null?TDataGridPagerMode::NextPrev : $this->_mode;
+ }
+
+ /**
+ * @param TDataGridPagerMode pager mode.
+ */
+ public function setMode($value)
+ {
+ $this->_mode=TPropertyValue::ensureEnum($value,'TDataGridPagerMode');
+ }
+
+ /**
+ * @return TDataGridPagerButtonType the type of command button. Defaults to TDataGridPagerButtonType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->_buttonType===null?TDataGridPagerButtonType::LinkButton:$this->_buttonType;
+ }
+
+ /**
+ * @param TDataGridPagerButtonType the type of command button
+ */
+ public function setButtonType($value)
+ {
+ $this->_buttonType=TPropertyValue::ensureEnum($value,'TDataGridPagerButtonType');
+ }
+
+ /**
+ * @return string text for the next page button. Defaults to '>'.
+ */
+ public function getNextPageText()
+ {
+ return $this->_nextText===null?'>':$this->_nextText;
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setNextPageText($value)
+ {
+ $this->_nextText=$value;
+ }
+
+ /**
+ * @return string text for the previous page button. Defaults to '<'.
+ */
+ public function getPrevPageText()
+ {
+ return $this->_prevText===null?'<':$this->_prevText;
+ }
+
+ /**
+ * @param string text for the previous page button.
+ */
+ public function setPrevPageText($value)
+ {
+ $this->_prevText=$value;
+ }
+
+ /**
+ * @return string text for the first page button. Defaults to '<<'.
+ */
+ public function getFirstPageText()
+ {
+ return $this->_firstText===null?'<<':$this->_firstText;
+ }
+
+ /**
+ * @param string text for the first page button.
+ */
+ public function setFirstPageText($value)
+ {
+ $this->_firstText=$value;
+ }
+
+ /**
+ * @return string text for the last page button. Defaults to '>>'.
+ */
+ public function getLastPageText()
+ {
+ return $this->_lastText===null?'>>':$this->_lastText;
+ }
+
+ /**
+ * @param string text for the last page button.
+ */
+ public function setLastPageText($value)
+ {
+ $this->_lastText=$value;
+ }
+
+ /**
+ * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
+ */
+ public function getPageButtonCount()
+ {
+ return $this->_buttonCount===null?10:$this->_buttonCount;
+ }
+
+ /**
+ * @param integer maximum number of pager buttons to be displayed
+ * @throws TInvalidDataValueException if the value is less than 1.
+ */
+ public function setPageButtonCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('datagridpagerstyle_pagebuttoncount_invalid');
+ $this->_buttonCount=$value;
+ }
+
+ /**
+ * @return TDataGridPagerPosition where the pager is to be displayed. Defaults to TDataGridPagerPosition::Bottom.
+ */
+ public function getPosition()
+ {
+ return $this->_position===null?TDataGridPagerPosition::Bottom:$this->_position;
+ }
+
+ /**
+ * @param TDataGridPagerPosition where the pager is to be displayed.
+ */
+ public function setPosition($value)
+ {
+ $this->_position=TPropertyValue::ensureEnum($value,'TDataGridPagerPosition');
+ }
+
+ /**
+ * @return boolean whether the pager is visible. Defaults to true.
+ */
+ public function getVisible()
+ {
+ return $this->_visible===null?true:$this->_visible;
+ }
+
+ /**
+ * @param boolean whether the pager is visible.
+ */
+ public function setVisible($value)
+ {
+ $this->_visible=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Resets the style to the original empty state.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_visible=null;
+ $this->_position=null;
+ $this->_buttonCount=null;
+ $this->_prevText=null;
+ $this->_nextText=null;
+ $this->_mode=null;
+ $this->_buttonType=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($style->_visible!==null)
+ $this->_visible=$style->_visible;
+ if($style->_position!==null)
+ $this->_position=$style->_position;
+ if($style->_buttonCount!==null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($style->_prevText!==null)
+ $this->_prevText=$style->_prevText;
+ if($style->_nextText!==null)
+ $this->_nextText=$style->_nextText;
+ if($style->_mode!==null)
+ $this->_mode=$style->_mode;
+ if($style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TDataGridPagerStyle)
+ {
+ if($this->_visible===null)
+ $this->_visible=$style->_visible;
+ if($this->_position===null)
+ $this->_position=$style->_position;
+ if($this->_buttonCount===null)
+ $this->_buttonCount=$style->_buttonCount;
+ if($this->_prevText===null)
+ $this->_prevText=$style->_prevText;
+ if($this->_nextText===null)
+ $this->_nextText=$style->_nextText;
+ if($this->_mode===null)
+ $this->_mode=$style->_mode;
+ if($this->_buttonType===null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataList.php b/framework/Web/UI/WebControls/TDataList.php
index 43980c0c..49e9c749 100644
--- a/framework/Web/UI/WebControls/TDataList.php
+++ b/framework/Web/UI/WebControls/TDataList.php
@@ -1,1766 +1,1766 @@
-<?php
-/**
- * TDataList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TBaseDataList class
- */
-Prado::using('System.Web.UI.WebControls.TBaseDataList');
-/**
- * Includes TRepeatInfo class
- */
-Prado::using('System.Web.UI.WebControls.TRepeatInfo');
-
-/**
- * TDataList class
- *
- * TDataList represents a data bound and updatable list control.
- *
- * Like {@link TRepeater}, TDataList displays its content repeatedly based on
- * the data fetched from {@link setDataSource DataSource}.
- * The repeated contents in TDataList are called items, which are controls and
- * can be accessed through {@link getItems Items}. When {@link dataBind()} is
- * invoked, TDataList creates an item for each row of data and binds the data
- * row to the item. Optionally, a TDataList can have a header, a footer and/or
- * separators between items.
- *
- * TDataList differs from {@link TRepeater} in that it supports tiling the items
- * in different manners and it maintains status of items to handle data update.
- *
- * The layout of the repeated contents are specified by inline templates.
- * TDataList items, header, footer, etc. are being instantiated with the corresponding
- * templates when data is being bound to the repeater.
- *
- * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
- * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
- * as an external template (in fact, it can also be non-templated controls).
- *
- * A renderer can be any control class.
- * - If the class implements {@link IDataRenderer}, the <b>Data</b>
- * property will be set as the data row during databinding. Many PRADO controls
- * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
- * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
- * as the zero-based index of the item in the datalist item collection, and
- * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
- * {@link TDataListItemRenderer} may be used as the convenient base class which
- * already implements {@link IDataItemRenderer}.
- *
- * The following properties are used to specify different types of template and renderer
- * for a datalist:
- * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
- * for each repeated row of data
- * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
- * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
- * will be used instead.
- * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
- * for the datalist header.
- * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
- * for the datalist footer.
- * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
- * for content to be displayed between items.
- * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
- * used when data bound to the datalist is empty.
- * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
- * for the row being editted.
- * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
- * for the row being selected.
- *
- * If a content type is defined with both a template and a renderer, the latter takes precedence.
- *
- * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
- * - create item based on templates or renderers
- * - set the row of data to the item
- * - raise {@link onItemCreated OnItemCreated}:
- * - add the item as a child control
- * - call dataBind() of the item
- * - raise {@link onItemDataBound OnItemDataBound}:
- *
- * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
- * within some datalist item raises a <b>OnCommand</b> event. Therefore,
- * you can handle all sorts of <b>OnCommand</b> event in a central place by
- * writing an event handler for {@link onItemCommand OnItemCommand}.
- *
- * An additional event is raised if the <b>OnCommand</b> event has one of the following
- * command names:
- * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
- * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
- * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
- * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
- * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
- *
- * TDataList provides a few properties to support tiling the items.
- * The number of columns used to display the data items is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
- * which can take one of the following values:
- * - Table (default): items are organized using HTML table and cells.
- * When using this layout, one can set {@link setCellPadding CellPadding} and
- * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
- * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
- * to add a table caption with the specified alignment.
- * - Flow: items are organized using HTML spans and breaks.
- * - Raw: TDataList does not generate any HTML tags to do the tiling.
- *
- * Items in TDataList can be in one of the three status: normal browsing,
- * being editted and being selected. To change the status of a particular
- * item, set {@link setSelectedItemIndex SelectedItemIndex} or
- * {@link setEditItemIndex EditItemIndex}. The former will change
- * the indicated item to selected mode, which will cause the item to
- * use {@link setSelectedItemTemplate SelectedItemTemplate} or
- * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
- * The latter will change the indicated item to edit mode and to use corresponding
- * template or renderer.
- * Note, if an item is in edit mode, then selecting this item will have no effect.
- *
- * Different styles may be applied to items in different status. The style
- * application is performed in a hierarchical way: Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * - item's own style
- * - {@link getItemStyle ItemStyle}
- * - {@link getAlternatingItemStyle AlternatingItemStyle}
- * - {@link getSelectedItemStyle SelectedItemStyle}
- * - {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- *
- * When a page containing a datalist is post back, the datalist will restore automatically
- * all its contents, including items, header, footer and separators.
- * However, the data row associated with each item will not be recovered and become null.
- * To access the data, use one of the following ways:
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified datalist item and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
- * Be aware though, if the size of your dataset is big, your page size will become big. Some
- * complex data may also have serializing problem if saved in viewstate.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
-{
- /**
- * Command name that TDataList understands. They are case-insensitive.
- */
- const CMD_SELECT='Select';
- const CMD_EDIT='Edit';
- const CMD_UPDATE='Update';
- const CMD_DELETE='Delete';
- const CMD_CANCEL='Cancel';
-
- /**
- * @var TDataListItemCollection item list
- */
- private $_items=null;
- /**
- * @var Itemplate various item templates
- */
- private $_itemTemplate=null;
- private $_emptyTemplate=null;
- private $_alternatingItemTemplate=null;
- private $_selectedItemTemplate=null;
- private $_editItemTemplate=null;
- private $_headerTemplate=null;
- private $_footerTemplate=null;
- private $_separatorTemplate=null;
- /**
- * @var TControl header item
- */
- private $_header=null;
- /**
- * @var TControl footer item
- */
- private $_footer=null;
-
- /**
- * @return TDataListItemCollection item list
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TDataListItemCollection;
- return $this->_items;
- }
-
- /**
- * @return integer number of items
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * @return string the class name for datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist items.
- * This property takes precedence over {@link getItemTemplate ItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setItemTemplate
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getAlternatingItemRenderer()
- {
- return $this->getViewState('AlternatingItemRenderer','');
- }
-
- /**
- * Sets the alternative item renderer class.
- *
- * If not empty, the class will be used to instantiate as alternative datalist items.
- * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setAlternatingItemTemplate
- * @since 3.1.0
- */
- public function setAlternatingItemRenderer($value)
- {
- $this->setViewState('AlternatingItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being editted.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEditItemTemplate
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSelectedItemRenderer()
- {
- return $this->getViewState('SelectedItemRenderer','');
- }
-
- /**
- * Sets the renderer class for the datalist item being selected.
- *
- * If not empty, the class will be used to instantiate as the datalist item.
- * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSelectedItemTemplate
- * @since 3.1.0
- */
- public function setSelectedItemRenderer($value)
- {
- $this->setViewState('SelectedItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSeparatorRenderer()
- {
- return $this->getViewState('SeparatorRenderer','');
- }
-
- /**
- * Sets the datalist item separator renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist item separators.
- * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSeparatorTemplate
- * @since 3.1.0
- */
- public function setSeparatorRenderer($value)
- {
- $this->setViewState('SeparatorRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist header item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the datalist header renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist header item.
- * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setHeaderTemplate
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the datalist footer renderer class.
- *
- * If not empty, the class will be used to instantiate as datalist footer item.
- * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setFooterTemplate
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEmptyRenderer()
- {
- return $this->getViewState('EmptyRenderer','');
- }
-
- /**
- * Sets the datalist empty renderer class.
- *
- * The empty renderer is created as the child of the datalist
- * if data bound to the datalist is empty.
- * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEmptyTemplate
- * @since 3.1.0
- */
- public function setEmptyRenderer($value)
- {
- $this->setViewState('EmptyRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the template for item
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the template for item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for item
- */
- public function getItemStyle()
- {
- if(($style=$this->getViewState('ItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('ItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the template for each alternating item
- */
- public function getAlternatingItemTemplate()
- {
- return $this->_alternatingItemTemplate;
- }
-
- /**
- * @param ITemplate the template for each alternating item
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setAlternatingItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_alternatingItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
- }
-
- /**
- * @return TTableItemStyle the style for each alternating item
- */
- public function getAlternatingItemStyle()
- {
- if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('AlternatingItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the selected item template
- */
- public function getSelectedItemTemplate()
- {
- return $this->_selectedItemTemplate;
- }
-
- /**
- * @param ITemplate the selected item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSelectedItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_selectedItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for selected item
- */
- public function getSelectedItemStyle()
- {
- if(($style=$this->getViewState('SelectedItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SelectedItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the edit item template
- */
- public function getEditItemTemplate()
- {
- return $this->_editItemTemplate;
- }
-
- /**
- * @param ITemplate the edit item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEditItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_editItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for edit item
- */
- public function getEditItemStyle()
- {
- if(($style=$this->getViewState('EditItemStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('EditItemStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for header
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for footer
- */
- public function getFooterStyle()
- {
- if(($style=$this->getViewState('FooterStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('FooterStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TControl the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the datalist
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the datalist
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
- }
-
- /**
- * @return ITemplate the separator template
- */
- public function getSeparatorTemplate()
- {
- return $this->_separatorTemplate;
- }
-
- /**
- * @param ITemplate the separator template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSeparatorTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_separatorTemplate=$value;
- else
- throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
- }
-
- /**
- * @return TTableItemStyle the style for separator
- */
- public function getSeparatorStyle()
- {
- if(($style=$this->getViewState('SeparatorStyle',null))===null)
- {
- $style=new TTableItemStyle;
- $this->setViewState('SeparatorStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return integer the zero-based index of the selected item in {@link getItems Items}.
- * A value -1 means no item selected.
- */
- public function getSelectedItemIndex()
- {
- return $this->getViewState('SelectedItemIndex',-1);
- }
-
- /**
- * Selects an item by its index in {@link getItems Items}.
- * Previously selected item will be un-selected.
- * If the item to be selected is already in edit mode, it will remain in edit mode.
- * If the index is less than 0, any existing selection will be cleared up.
- * @param integer the selected item index
- */
- public function setSelectedItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getSelectedItemIndex())!==$value)
- {
- $this->setViewState('SelectedItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- {
- $item=$items->itemAt($current);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- }
- if($value>=0 && $value<$itemCount)
- {
- $item=$items->itemAt($value);
- if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
- $item->setItemType(TListItemType::SelectedItem);
- }
- }
- }
-
- /**
- * @return TControl the selected item, null if no item is selected.
- */
- public function getSelectedItem()
- {
- $index=$this->getSelectedItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return mixed the key value of the currently selected item
- * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
- */
- public function getSelectedDataKey()
- {
- if($this->getDataKeyField()==='')
- throw new TInvalidOperationException('datalist_datakeyfield_required');
- $index=$this->getSelectedItemIndex();
- $dataKeys=$this->getDataKeys();
- if($index>=0 && $index<$dataKeys->getCount())
- return $dataKeys->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return integer the zero-based index of the edit item in {@link getItems Items}.
- * A value -1 means no item is in edit mode.
- */
- public function getEditItemIndex()
- {
- return $this->getViewState('EditItemIndex',-1);
- }
-
- /**
- * Edits an item by its index in {@link getItems Items}.
- * Previously editting item will change to normal item state.
- * If the index is less than 0, any existing edit item will be cleared up.
- * @param integer the edit item index
- */
- public function setEditItemIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- if(($current=$this->getEditItemIndex())!==$value)
- {
- $this->setViewState('EditItemIndex',$value,-1);
- $items=$this->getItems();
- $itemCount=$items->getCount();
- if($current>=0 && $current<$itemCount)
- $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
- if($value>=0 && $value<$itemCount)
- $items->itemAt($value)->setItemType(TListItemType::EditItem);
- }
- }
-
- /**
- * @return TControl the edit item
- */
- public function getEditItem()
- {
- $index=$this->getEditItemIndex();
- $items=$this->getItems();
- if($index>=0 && $index<$items->getCount())
- return $items->itemAt($index);
- else
- return null;
- }
-
- /**
- * @return boolean whether the header should be shown. Defaults to true.
- */
- public function getShowHeader()
- {
- return $this->getViewState('ShowHeader',true);
- }
-
- /**
- * @param boolean whether to show header
- */
- public function setShowHeader($value)
- {
- $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the footer should be shown. Defaults to true.
- */
- public function getShowFooter()
- {
- return $this->getViewState('ShowFooter',true);
- }
-
- /**
- * @param boolean whether to show footer
- */
- public function setShowFooter($value)
- {
- $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TRepeatInfo repeat information (primarily used by control developers)
- */
- protected function getRepeatInfo()
- {
- if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
- {
- $repeatInfo=new TRepeatInfo;
- $this->setViewState('RepeatInfo',$repeatInfo,null);
- }
- return $repeatInfo;
- }
-
- /**
- * @return string caption of the table layout
- */
- public function getCaption()
- {
- return $this->getRepeatInfo()->getCaption();
- }
-
- /**
- * @param string caption of the table layout
- */
- public function setCaption($value)
- {
- $this->getRepeatInfo()->setCaption($value);
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getRepeatInfo()->getCaptionAlign();
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout.
- */
- public function setCaptionAlign($value)
- {
- $this->getRepeatInfo()->setCaptionAlign($value);
- }
-
- /**
- * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->getRepeatInfo()->getRepeatColumns();
- }
-
- /**
- * @param integer the number of columns that the list should be displayed with.
- */
- public function setRepeatColumns($value)
- {
- $this->getRepeatInfo()->setRepeatColumns($value);
- }
-
- /**
- * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
- */
- public function getRepeatDirection()
- {
- return $this->getRepeatInfo()->getRepeatDirection();
- }
-
- /**
- * @param TRepeatDirection the direction of traversing the list
- */
- public function setRepeatDirection($value)
- {
- $this->getRepeatInfo()->setRepeatDirection($value);
- }
-
- /**
- * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
- */
- public function getRepeatLayout()
- {
- return $this->getRepeatInfo()->getRepeatLayout();
- }
-
- /**
- * @param TRepeatLayout how the list should be displayed, using table or using line breaks
- */
- public function setRepeatLayout($value)
- {
- $this->getRepeatInfo()->setRepeatLayout($value);
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * datalist items and their child controls.
- * If the event parameter is {@link TDataListCommandEventParameter} and
- * the command name is a recognized one, which includes 'select', 'edit',
- * 'delete', 'update', and 'cancel' (case-insensitive), then a
- * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TDataListCommandEventParameter)
- {
- $this->onItemCommand($param);
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_SELECT)===0)
- {
- if(($item=$param->getItem()) instanceof IItemDataRenderer)
- $this->setSelectedItemIndex($item->getItemIndex());
- $this->onSelectedIndexChanged($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_EDIT)===0)
- {
- $this->onEditCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_DELETE)===0)
- {
- $this->onDeleteCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_UPDATE)===0)
- {
- $this->onUpdateCommand($param);
- return true;
- }
- else if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelCommand($param);
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked after a data list item is created and instantiated with
- * template, but before added to the page hierarchy.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked right after an item is data bound.
- * The datalist item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TDataListItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event.
- * @param TDataListCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnEditCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onEditCommand($param)
- {
- $this->raiseEvent('OnEditCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnDeleteCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onDeleteCommand($param)
- {
- $this->raiseEvent('OnDeleteCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnUpdateCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onUpdateCommand($param)
- {
- $this->raiseEvent('OnUpdateCommand',$this,$param);
- }
-
- /**
- * Raises <b>OnCancelCommand</b> event.
- * This method is invoked when a child control of the data list
- * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
- * @param TDataListCommandEventParameter event parameter
- */
- public function onCancelCommand($param)
- {
- $this->raiseEvent('OnCancelCommand',$this,$param);
- }
-
- /**
- * Returns a value indicating whether this control contains header item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has header
- */
- public function getHasHeader()
- {
- return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains footer item.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean whether the datalist has footer
- */
- public function getHasFooter()
- {
- return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
- }
-
- /**
- * Returns a value indicating whether this control contains separator items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @return boolean always false.
- */
- public function getHasSeparators()
- {
- return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- }
-
- /**
- * Returns a style used for rendering items.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer index of the item being rendered
- * @return TStyle item style
- */
- public function generateItemStyle($itemType,$index)
- {
- if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
- {
- $style=$item->getStyle();
- $item->clearStyle();
- return $style;
- }
- else
- return null;
- }
-
- /**
- * Renders an item in the list.
- * This method is required by {@link IRepeatInfoUser} interface.
- * @param THtmlWriter writer for rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the item in the item list
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index)
- {
- $item=$this->getItem($itemType,$index);
- if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
- $item->setTagName('div');
- $item->renderControl($writer);
- }
-
- /**
- * @param TListItemType item type
- * @param integer item index
- * @return TControl data list item with the specified item type and index
- */
- private function getItem($itemType,$index)
- {
- switch($itemType)
- {
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- case TListItemType::EditItem:
- return $this->getItems()->itemAt($index);
- case TListItemType::Header:
- return $this->getControls()->itemAt(0);
- case TListItemType::Footer:
- return $this->getControls()->itemAt($this->getControls()->getCount()-1);
- case TListItemType::Separator:
- $i=$index+$index+1;
- if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
- $i++;
- return $this->getControls()->itemAt($i);
- }
- return null;
- }
-
- /**
- * Creates a datalist item.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @return TControl the created item, null if item is not created
- */
- private function createItemInternal($itemIndex,$itemType)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a datalist item and performs databinding.
- * This method invokes {@link createItem} to create a new datalist item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @param mixed data to be associated with the item
- * @return TControl the created item, null if item is not created
- */
- private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TDataListItemEventParameter($item);
- if($item instanceof IDataRenderer)
- $item->setData($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- return $item;
- }
- else
- return null;
- }
-
- private function getAlternatingItemDisplay()
- {
- if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return array($classPath,$this->_alternatingItemTemplate);
- }
-
- private function getSelectedItemDisplay($itemIndex)
- {
- if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
- {
- if($itemIndex%2===0)
- return array($this->getItemRenderer(),$this->_itemTemplate);
- else
- return $this->getAlternatingItemDisplay();
- }
- else
- return array($classPath,$this->_selectedItemTemplate);
- }
-
- private function getEditItemDisplay($itemIndex)
- {
- if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
- return $this->getSelectedItemDisplay($itemIndex);
- else
- return array($classPath,$this->_editItemTemplate);
- }
-
- /**
- * Creates a datalist item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TControl created datalist item
- */
- protected function createItem($itemIndex,$itemType)
- {
- $template=null;
- $classPath=null;
- switch($itemType)
- {
- case TListItemType::Item :
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- break;
- case TListItemType::AlternatingItem :
- list($classPath,$template)=$this->getAlternatingItemDisplay();
- break;
- case TListItemType::SelectedItem:
- list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
- break;
- case TListItemType::EditItem:
- list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
- break;
- case TListItemType::Header :
- $classPath=$this->getHeaderRenderer();
- $template=$this->_headerTemplate;
- break;
- case TListItemType::Footer :
- $classPath=$this->getFooterRenderer();
- $template=$this->_footerTemplate;
- break;
- case TListItemType::Separator :
- $classPath=$this->getSeparatorRenderer();
- $template=$this->_separatorTemplate;
- break;
- default:
- throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
- }
- if($classPath!=='')
- {
- $item=Prado::createComponent($classPath);
- if($item instanceof IItemDataRenderer)
- {
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- }
- }
- else if($template!==null)
- {
- $item=new TDataListItem;
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- $template->instantiateIn($item);
- }
- else
- $item=null;
-
- return $item;
- }
-
- /**
- * Creates empty datalist content.
- */
- protected function createEmptyContent()
- {
- if(($classPath=$this->getEmptyRenderer())!=='')
- $this->getControls()->add(Prado::createComponent($classPath));
- else if($this->_emptyTemplate!==null)
- $this->_emptyTemplate->instantiateIn($this);
- }
-
- /**
- * Applies styles to items, header, footer and separators.
- * Item styles are applied in a hierarchical way. Style in higher hierarchy
- * will inherit from styles in lower hierarchy.
- * Starting from the lowest hierarchy, the item styles include
- * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
- * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
- * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
- * {@link getEditItemStyle EditItemStyle} will also have red background color
- * unless it is set to a different value explicitly.
- */
- protected function applyItemStyles()
- {
- $itemStyle=$this->getViewState('ItemStyle',null);
-
- $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
- if($itemStyle!==null)
- {
- if($alternatingItemStyle===null)
- $alternatingItemStyle=$itemStyle;
- else
- $alternatingItemStyle->mergeWith($itemStyle);
- }
-
- $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
-
- $editItemStyle=$this->getViewState('EditItemStyle',null);
- if($selectedItemStyle!==null)
- {
- if($editItemStyle===null)
- $editItemStyle=$selectedItemStyle;
- else
- $editItemStyle->mergeWith($selectedItemStyle);
- }
-
- // apply header style if any
- if($this->_header!==null && $this->_header instanceof IStyleable)
- {
- if($headerStyle=$this->getViewState('HeaderStyle',null))
- $this->_header->getStyle()->mergeWith($headerStyle);
- }
-
- // apply footer style if any
- if($this->_footer!==null && $this->_footer instanceof IStyleable)
- {
- if($footerStyle=$this->getViewState('FooterStyle',null))
- $this->_footer->getStyle()->mergeWith($footerStyle);
- }
-
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
-
- // apply item styles if any
- foreach($this->getItems() as $index=>$item)
- {
- if($index===$editIndex)
- $style=$editItemStyle;
- else if($index===$selectedIndex)
- $style=$selectedItemStyle;
- else if($index%2===0)
- $style=$itemStyle;
- else
- $style=$alternatingItemStyle;
- if($style && $item instanceof IStyleable)
- $item->getStyle()->mergeWith($style);
- }
-
- // apply separator style if any
- if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
- {
- $controls=$this->getControls();
- $count=$controls->getCount();
- for($i=$this->_header?2:1;$i<$count;$i+=2)
- {
- if(($separator=$controls->itemAt($i)) instanceof IStyleable)
- $separator->getStyle()->mergeWith($separatorStyle);
- }
- }
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getIsDataBound())
- $this->restoreItemsFromViewState();
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Clears up all items in the data list.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- }
-
- /**
- * Creates data list items based on viewstate information.
- */
- protected function restoreItemsFromViewState()
- {
- $this->reset();
- if(($itemCount=$this->getViewState('ItemCount',0))>0)
- {
- $items=$this->getItems();
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $this->_header=$this->createItemInternal(-1,TListItemType::Header);
- for($i=0;$i<$itemCount;++$i)
- {
- if($hasSeparator && $i>0)
- $this->createItemInternal($i-1,TListItemType::Separator);
- if($i===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($i===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemInternal($i,$itemType));
- }
- $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
- }
- else
- $this->createEmptyContent();
- $this->clearChildState();
- }
-
- /**
- * Performs databinding to populate data list items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
- $itemIndex=0;
- $items=$this->getItems();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $selectedIndex=$this->getSelectedItemIndex();
- $editIndex=$this->getEditItemIndex();
- foreach($data as $key=>$dataItem)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($dataItem,$keyField));
- else
- $keys->add($key);
- if($itemIndex===0)
- $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
- if($hasSeparator && $itemIndex>0)
- $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
- if($itemIndex===$editIndex)
- $itemType=TListItemType::EditItem;
- else if($itemIndex===$selectedIndex)
- $itemType=TListItemType::SelectedItem;
- else
- $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
- $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
- $itemIndex++;
- }
- if($itemIndex>0)
- $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
- else
- {
- $this->createEmptyContent();
- $this->dataBindChildren();
- }
- $this->setViewState('ItemCount',$itemIndex,0);
- }
-
- /**
- * Renders the data list control.
- * This method overrides the parent implementation.
- * @param THtmlWriter writer for rendering purpose.
- */
- public function render($writer)
- {
- if($this->getHasControls())
- {
- if($this->getItemCount()>0)
- {
- $this->applyItemStyles();
- $repeatInfo=$this->getRepeatInfo();
- $repeatInfo->renderRepeater($writer,$this);
- }
- else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
- parent::render($writer);
- }
- }
-}
-
-
-/**
- * TDataListItemEventParameter class
- *
- * TDataListItemEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
- * The {@link getItem Item} property indicates the DataList item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemEventParameter extends TEventParameter
-{
- /**
- * The datalist item control responsible for the event.
- * @var TControl
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TControl DataList item related with the corresponding event
- */
- public function __construct($item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TControl datalist item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TDataListCommandEventParameter class
- *
- * TDataListCommandEventParameter encapsulates the parameter data for
- * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
- *
- * The {@link getItem Item} property indicates the DataList item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TControl the datalist item control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>OnCommand</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl datalist item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TControl the datalist item control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TDataListItem class
- *
- * A TDataListItem control represents an item in the {@link TDataList} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of DataList
- */
- private $_itemIndex;
- /**
- * type of the TDataListItem
- * @var TListItemType
- */
- private $_itemType;
- /**
- * value of the data associated with this item
- * @var mixed
- */
- private $_data;
-
- private $_tagName='span';
-
- /**
- * Returns the tag name used for this control.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return $this->_tagName;
- }
-
- /**
- * @param string tag name of the control to be rendered
- */
- public function setTagName($value)
- {
- $this->_tagName=$value;
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by a datalist item.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * @return integer zero-based index of the item in the item collection of datalist
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-/**
- * TDataListItemCollection class.
- *
- * TDataListItemCollection represents a collection of data list items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataListItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only TControl descendants.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TBaseDataList class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseDataList');
+/**
+ * Includes TRepeatInfo class
+ */
+Prado::using('System.Web.UI.WebControls.TRepeatInfo');
+
+/**
+ * TDataList class
+ *
+ * TDataList represents a data bound and updatable list control.
+ *
+ * Like {@link TRepeater}, TDataList displays its content repeatedly based on
+ * the data fetched from {@link setDataSource DataSource}.
+ * The repeated contents in TDataList are called items, which are controls and
+ * can be accessed through {@link getItems Items}. When {@link dataBind()} is
+ * invoked, TDataList creates an item for each row of data and binds the data
+ * row to the item. Optionally, a TDataList can have a header, a footer and/or
+ * separators between items.
+ *
+ * TDataList differs from {@link TRepeater} in that it supports tiling the items
+ * in different manners and it maintains status of items to handle data update.
+ *
+ * The layout of the repeated contents are specified by inline templates.
+ * TDataList items, header, footer, etc. are being instantiated with the corresponding
+ * templates when data is being bound to the repeater.
+ *
+ * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
+ * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
+ * as an external template (in fact, it can also be non-templated controls).
+ *
+ * A renderer can be any control class.
+ * - If the class implements {@link IDataRenderer}, the <b>Data</b>
+ * property will be set as the data row during databinding. Many PRADO controls
+ * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
+ * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
+ * as the zero-based index of the item in the datalist item collection, and
+ * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
+ * {@link TDataListItemRenderer} may be used as the convenient base class which
+ * already implements {@link IDataItemRenderer}.
+ *
+ * The following properties are used to specify different types of template and renderer
+ * for a datalist:
+ * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
+ * for each repeated row of data
+ * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
+ * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
+ * will be used instead.
+ * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
+ * for the datalist header.
+ * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
+ * for the datalist footer.
+ * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
+ * for content to be displayed between items.
+ * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
+ * used when data bound to the datalist is empty.
+ * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
+ * for the row being editted.
+ * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
+ * for the row being selected.
+ *
+ * If a content type is defined with both a template and a renderer, the latter takes precedence.
+ *
+ * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
+ * - create item based on templates or renderers
+ * - set the row of data to the item
+ * - raise {@link onItemCreated OnItemCreated}:
+ * - add the item as a child control
+ * - call dataBind() of the item
+ * - raise {@link onItemDataBound OnItemDataBound}:
+ *
+ * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
+ * within some datalist item raises a <b>OnCommand</b> event. Therefore,
+ * you can handle all sorts of <b>OnCommand</b> event in a central place by
+ * writing an event handler for {@link onItemCommand OnItemCommand}.
+ *
+ * An additional event is raised if the <b>OnCommand</b> event has one of the following
+ * command names:
+ * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
+ * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
+ * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
+ * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
+ * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
+ *
+ * TDataList provides a few properties to support tiling the items.
+ * The number of columns used to display the data items is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
+ * which can take one of the following values:
+ * - Table (default): items are organized using HTML table and cells.
+ * When using this layout, one can set {@link setCellPadding CellPadding} and
+ * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
+ * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
+ * to add a table caption with the specified alignment.
+ * - Flow: items are organized using HTML spans and breaks.
+ * - Raw: TDataList does not generate any HTML tags to do the tiling.
+ *
+ * Items in TDataList can be in one of the three status: normal browsing,
+ * being editted and being selected. To change the status of a particular
+ * item, set {@link setSelectedItemIndex SelectedItemIndex} or
+ * {@link setEditItemIndex EditItemIndex}. The former will change
+ * the indicated item to selected mode, which will cause the item to
+ * use {@link setSelectedItemTemplate SelectedItemTemplate} or
+ * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
+ * The latter will change the indicated item to edit mode and to use corresponding
+ * template or renderer.
+ * Note, if an item is in edit mode, then selecting this item will have no effect.
+ *
+ * Different styles may be applied to items in different status. The style
+ * application is performed in a hierarchical way: Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * - item's own style
+ * - {@link getItemStyle ItemStyle}
+ * - {@link getAlternatingItemStyle AlternatingItemStyle}
+ * - {@link getSelectedItemStyle SelectedItemStyle}
+ * - {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ *
+ * When a page containing a datalist is post back, the datalist will restore automatically
+ * all its contents, including items, header, footer and separators.
+ * However, the data row associated with each item will not be recovered and become null.
+ * To access the data, use one of the following ways:
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified datalist item and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
+ * Be aware though, if the size of your dataset is big, your page size will become big. Some
+ * complex data may also have serializing problem if saved in viewstate.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
+{
+ /**
+ * Command name that TDataList understands. They are case-insensitive.
+ */
+ const CMD_SELECT='Select';
+ const CMD_EDIT='Edit';
+ const CMD_UPDATE='Update';
+ const CMD_DELETE='Delete';
+ const CMD_CANCEL='Cancel';
+
+ /**
+ * @var TDataListItemCollection item list
+ */
+ private $_items=null;
+ /**
+ * @var Itemplate various item templates
+ */
+ private $_itemTemplate=null;
+ private $_emptyTemplate=null;
+ private $_alternatingItemTemplate=null;
+ private $_selectedItemTemplate=null;
+ private $_editItemTemplate=null;
+ private $_headerTemplate=null;
+ private $_footerTemplate=null;
+ private $_separatorTemplate=null;
+ /**
+ * @var TControl header item
+ */
+ private $_header=null;
+ /**
+ * @var TControl footer item
+ */
+ private $_footer=null;
+
+ /**
+ * @return TDataListItemCollection item list
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TDataListItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return integer number of items
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * @return string the class name for datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist items.
+ * This property takes precedence over {@link getItemTemplate ItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setItemTemplate
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getAlternatingItemRenderer()
+ {
+ return $this->getViewState('AlternatingItemRenderer','');
+ }
+
+ /**
+ * Sets the alternative item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as alternative datalist items.
+ * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setAlternatingItemTemplate
+ * @since 3.1.0
+ */
+ public function setAlternatingItemRenderer($value)
+ {
+ $this->setViewState('AlternatingItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being editted.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEditItemTemplate
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSelectedItemRenderer()
+ {
+ return $this->getViewState('SelectedItemRenderer','');
+ }
+
+ /**
+ * Sets the renderer class for the datalist item being selected.
+ *
+ * If not empty, the class will be used to instantiate as the datalist item.
+ * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSelectedItemTemplate
+ * @since 3.1.0
+ */
+ public function setSelectedItemRenderer($value)
+ {
+ $this->setViewState('SelectedItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSeparatorRenderer()
+ {
+ return $this->getViewState('SeparatorRenderer','');
+ }
+
+ /**
+ * Sets the datalist item separator renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist item separators.
+ * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSeparatorTemplate
+ * @since 3.1.0
+ */
+ public function setSeparatorRenderer($value)
+ {
+ $this->setViewState('SeparatorRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist header item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the datalist header renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist header item.
+ * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setHeaderTemplate
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the datalist footer renderer class.
+ *
+ * If not empty, the class will be used to instantiate as datalist footer item.
+ * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setFooterTemplate
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEmptyRenderer()
+ {
+ return $this->getViewState('EmptyRenderer','');
+ }
+
+ /**
+ * Sets the datalist empty renderer class.
+ *
+ * The empty renderer is created as the child of the datalist
+ * if data bound to the datalist is empty.
+ * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEmptyTemplate
+ * @since 3.1.0
+ */
+ public function setEmptyRenderer($value)
+ {
+ $this->setViewState('EmptyRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the template for item
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for item
+ */
+ public function getItemStyle()
+ {
+ if(($style=$this->getViewState('ItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('ItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the template for each alternating item
+ */
+ public function getAlternatingItemTemplate()
+ {
+ return $this->_alternatingItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for each alternating item
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setAlternatingItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_alternatingItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
+ }
+
+ /**
+ * @return TTableItemStyle the style for each alternating item
+ */
+ public function getAlternatingItemStyle()
+ {
+ if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('AlternatingItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the selected item template
+ */
+ public function getSelectedItemTemplate()
+ {
+ return $this->_selectedItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the selected item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSelectedItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_selectedItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for selected item
+ */
+ public function getSelectedItemStyle()
+ {
+ if(($style=$this->getViewState('SelectedItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SelectedItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the edit item template
+ */
+ public function getEditItemTemplate()
+ {
+ return $this->_editItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the edit item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEditItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_editItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for edit item
+ */
+ public function getEditItemStyle()
+ {
+ if(($style=$this->getViewState('EditItemStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('EditItemStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for header
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for footer
+ */
+ public function getFooterStyle()
+ {
+ if(($style=$this->getViewState('FooterStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('FooterStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TControl the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the datalist
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the datalist
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
+ }
+
+ /**
+ * @return ITemplate the separator template
+ */
+ public function getSeparatorTemplate()
+ {
+ return $this->_separatorTemplate;
+ }
+
+ /**
+ * @param ITemplate the separator template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSeparatorTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_separatorTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
+ }
+
+ /**
+ * @return TTableItemStyle the style for separator
+ */
+ public function getSeparatorStyle()
+ {
+ if(($style=$this->getViewState('SeparatorStyle',null))===null)
+ {
+ $style=new TTableItemStyle;
+ $this->setViewState('SeparatorStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return integer the zero-based index of the selected item in {@link getItems Items}.
+ * A value -1 means no item selected.
+ */
+ public function getSelectedItemIndex()
+ {
+ return $this->getViewState('SelectedItemIndex',-1);
+ }
+
+ /**
+ * Selects an item by its index in {@link getItems Items}.
+ * Previously selected item will be un-selected.
+ * If the item to be selected is already in edit mode, it will remain in edit mode.
+ * If the index is less than 0, any existing selection will be cleared up.
+ * @param integer the selected item index
+ */
+ public function setSelectedItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getSelectedItemIndex())!==$value)
+ {
+ $this->setViewState('SelectedItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ {
+ $item=$items->itemAt($current);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ }
+ if($value>=0 && $value<$itemCount)
+ {
+ $item=$items->itemAt($value);
+ if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
+ $item->setItemType(TListItemType::SelectedItem);
+ }
+ }
+ }
+
+ /**
+ * @return TControl the selected item, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ $index=$this->getSelectedItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return mixed the key value of the currently selected item
+ * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
+ */
+ public function getSelectedDataKey()
+ {
+ if($this->getDataKeyField()==='')
+ throw new TInvalidOperationException('datalist_datakeyfield_required');
+ $index=$this->getSelectedItemIndex();
+ $dataKeys=$this->getDataKeys();
+ if($index>=0 && $index<$dataKeys->getCount())
+ return $dataKeys->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return integer the zero-based index of the edit item in {@link getItems Items}.
+ * A value -1 means no item is in edit mode.
+ */
+ public function getEditItemIndex()
+ {
+ return $this->getViewState('EditItemIndex',-1);
+ }
+
+ /**
+ * Edits an item by its index in {@link getItems Items}.
+ * Previously editting item will change to normal item state.
+ * If the index is less than 0, any existing edit item will be cleared up.
+ * @param integer the edit item index
+ */
+ public function setEditItemIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ if(($current=$this->getEditItemIndex())!==$value)
+ {
+ $this->setViewState('EditItemIndex',$value,-1);
+ $items=$this->getItems();
+ $itemCount=$items->getCount();
+ if($current>=0 && $current<$itemCount)
+ $items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
+ if($value>=0 && $value<$itemCount)
+ $items->itemAt($value)->setItemType(TListItemType::EditItem);
+ }
+ }
+
+ /**
+ * @return TControl the edit item
+ */
+ public function getEditItem()
+ {
+ $index=$this->getEditItemIndex();
+ $items=$this->getItems();
+ if($index>=0 && $index<$items->getCount())
+ return $items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * @return boolean whether the header should be shown. Defaults to true.
+ */
+ public function getShowHeader()
+ {
+ return $this->getViewState('ShowHeader',true);
+ }
+
+ /**
+ * @param boolean whether to show header
+ */
+ public function setShowHeader($value)
+ {
+ $this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the footer should be shown. Defaults to true.
+ */
+ public function getShowFooter()
+ {
+ return $this->getViewState('ShowFooter',true);
+ }
+
+ /**
+ * @param boolean whether to show footer
+ */
+ public function setShowFooter($value)
+ {
+ $this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TRepeatInfo repeat information (primarily used by control developers)
+ */
+ protected function getRepeatInfo()
+ {
+ if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
+ {
+ $repeatInfo=new TRepeatInfo;
+ $this->setViewState('RepeatInfo',$repeatInfo,null);
+ }
+ return $repeatInfo;
+ }
+
+ /**
+ * @return string caption of the table layout
+ */
+ public function getCaption()
+ {
+ return $this->getRepeatInfo()->getCaption();
+ }
+
+ /**
+ * @param string caption of the table layout
+ */
+ public function setCaption($value)
+ {
+ $this->getRepeatInfo()->setCaption($value);
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getRepeatInfo()->getCaptionAlign();
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->getRepeatInfo()->setCaptionAlign($value);
+ }
+
+ /**
+ * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->getRepeatInfo()->getRepeatColumns();
+ }
+
+ /**
+ * @param integer the number of columns that the list should be displayed with.
+ */
+ public function setRepeatColumns($value)
+ {
+ $this->getRepeatInfo()->setRepeatColumns($value);
+ }
+
+ /**
+ * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
+ */
+ public function getRepeatDirection()
+ {
+ return $this->getRepeatInfo()->getRepeatDirection();
+ }
+
+ /**
+ * @param TRepeatDirection the direction of traversing the list
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->getRepeatInfo()->setRepeatDirection($value);
+ }
+
+ /**
+ * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->getRepeatInfo()->getRepeatLayout();
+ }
+
+ /**
+ * @param TRepeatLayout how the list should be displayed, using table or using line breaks
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->getRepeatInfo()->setRepeatLayout($value);
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * datalist items and their child controls.
+ * If the event parameter is {@link TDataListCommandEventParameter} and
+ * the command name is a recognized one, which includes 'select', 'edit',
+ * 'delete', 'update', and 'cancel' (case-insensitive), then a
+ * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TDataListCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_SELECT)===0)
+ {
+ if(($item=$param->getItem()) instanceof IItemDataRenderer)
+ $this->setSelectedItemIndex($item->getItemIndex());
+ $this->onSelectedIndexChanged($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_EDIT)===0)
+ {
+ $this->onEditCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_DELETE)===0)
+ {
+ $this->onDeleteCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_UPDATE)===0)
+ {
+ $this->onUpdateCommand($param);
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelCommand($param);
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked after a data list item is created and instantiated with
+ * template, but before added to the page hierarchy.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked right after an item is data bound.
+ * The datalist item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TDataListItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event.
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnEditCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onEditCommand($param)
+ {
+ $this->raiseEvent('OnEditCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeleteCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onDeleteCommand($param)
+ {
+ $this->raiseEvent('OnDeleteCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnUpdateCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onUpdateCommand($param)
+ {
+ $this->raiseEvent('OnUpdateCommand',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnCancelCommand</b> event.
+ * This method is invoked when a child control of the data list
+ * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
+ * @param TDataListCommandEventParameter event parameter
+ */
+ public function onCancelCommand($param)
+ {
+ $this->raiseEvent('OnCancelCommand',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether this control contains header item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has header
+ */
+ public function getHasHeader()
+ {
+ return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains footer item.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean whether the datalist has footer
+ */
+ public function getHasFooter()
+ {
+ return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
+ }
+
+ /**
+ * Returns a value indicating whether this control contains separator items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @return boolean always false.
+ */
+ public function getHasSeparators()
+ {
+ return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ }
+
+ /**
+ * Returns a style used for rendering items.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer index of the item being rendered
+ * @return TStyle item style
+ */
+ public function generateItemStyle($itemType,$index)
+ {
+ if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
+ {
+ $style=$item->getStyle();
+ $item->clearStyle();
+ return $style;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Renders an item in the list.
+ * This method is required by {@link IRepeatInfoUser} interface.
+ * @param THtmlWriter writer for rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the item in the item list
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index)
+ {
+ $item=$this->getItem($itemType,$index);
+ if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
+ $item->setTagName('div');
+ $item->renderControl($writer);
+ }
+
+ /**
+ * @param TListItemType item type
+ * @param integer item index
+ * @return TControl data list item with the specified item type and index
+ */
+ private function getItem($itemType,$index)
+ {
+ switch($itemType)
+ {
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ case TListItemType::EditItem:
+ return $this->getItems()->itemAt($index);
+ case TListItemType::Header:
+ return $this->getControls()->itemAt(0);
+ case TListItemType::Footer:
+ return $this->getControls()->itemAt($this->getControls()->getCount()-1);
+ case TListItemType::Separator:
+ $i=$index+$index+1;
+ if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
+ $i++;
+ return $this->getControls()->itemAt($i);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a datalist item.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemInternal($itemIndex,$itemType)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a datalist item and performs databinding.
+ * This method invokes {@link createItem} to create a new datalist item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @param mixed data to be associated with the item
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TDataListItemEventParameter($item);
+ if($item instanceof IDataRenderer)
+ $item->setData($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ private function getAlternatingItemDisplay()
+ {
+ if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return array($classPath,$this->_alternatingItemTemplate);
+ }
+
+ private function getSelectedItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
+ {
+ if($itemIndex%2===0)
+ return array($this->getItemRenderer(),$this->_itemTemplate);
+ else
+ return $this->getAlternatingItemDisplay();
+ }
+ else
+ return array($classPath,$this->_selectedItemTemplate);
+ }
+
+ private function getEditItemDisplay($itemIndex)
+ {
+ if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
+ return $this->getSelectedItemDisplay($itemIndex);
+ else
+ return array($classPath,$this->_editItemTemplate);
+ }
+
+ /**
+ * Creates a datalist item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TControl created datalist item
+ */
+ protected function createItem($itemIndex,$itemType)
+ {
+ $template=null;
+ $classPath=null;
+ switch($itemType)
+ {
+ case TListItemType::Item :
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ break;
+ case TListItemType::AlternatingItem :
+ list($classPath,$template)=$this->getAlternatingItemDisplay();
+ break;
+ case TListItemType::SelectedItem:
+ list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
+ break;
+ case TListItemType::EditItem:
+ list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
+ break;
+ case TListItemType::Header :
+ $classPath=$this->getHeaderRenderer();
+ $template=$this->_headerTemplate;
+ break;
+ case TListItemType::Footer :
+ $classPath=$this->getFooterRenderer();
+ $template=$this->_footerTemplate;
+ break;
+ case TListItemType::Separator :
+ $classPath=$this->getSeparatorRenderer();
+ $template=$this->_separatorTemplate;
+ break;
+ default:
+ throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
+ }
+ if($classPath!=='')
+ {
+ $item=Prado::createComponent($classPath);
+ if($item instanceof IItemDataRenderer)
+ {
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ }
+ }
+ else if($template!==null)
+ {
+ $item=new TDataListItem;
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ $template->instantiateIn($item);
+ }
+ else
+ $item=null;
+
+ return $item;
+ }
+
+ /**
+ * Creates empty datalist content.
+ */
+ protected function createEmptyContent()
+ {
+ if(($classPath=$this->getEmptyRenderer())!=='')
+ $this->getControls()->add(Prado::createComponent($classPath));
+ else if($this->_emptyTemplate!==null)
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Applies styles to items, header, footer and separators.
+ * Item styles are applied in a hierarchical way. Style in higher hierarchy
+ * will inherit from styles in lower hierarchy.
+ * Starting from the lowest hierarchy, the item styles include
+ * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
+ * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
+ * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
+ * {@link getEditItemStyle EditItemStyle} will also have red background color
+ * unless it is set to a different value explicitly.
+ */
+ protected function applyItemStyles()
+ {
+ $itemStyle=$this->getViewState('ItemStyle',null);
+
+ $alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
+ if($itemStyle!==null)
+ {
+ if($alternatingItemStyle===null)
+ $alternatingItemStyle=$itemStyle;
+ else
+ $alternatingItemStyle->mergeWith($itemStyle);
+ }
+
+ $selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
+
+ $editItemStyle=$this->getViewState('EditItemStyle',null);
+ if($selectedItemStyle!==null)
+ {
+ if($editItemStyle===null)
+ $editItemStyle=$selectedItemStyle;
+ else
+ $editItemStyle->mergeWith($selectedItemStyle);
+ }
+
+ // apply header style if any
+ if($this->_header!==null && $this->_header instanceof IStyleable)
+ {
+ if($headerStyle=$this->getViewState('HeaderStyle',null))
+ $this->_header->getStyle()->mergeWith($headerStyle);
+ }
+
+ // apply footer style if any
+ if($this->_footer!==null && $this->_footer instanceof IStyleable)
+ {
+ if($footerStyle=$this->getViewState('FooterStyle',null))
+ $this->_footer->getStyle()->mergeWith($footerStyle);
+ }
+
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+
+ // apply item styles if any
+ foreach($this->getItems() as $index=>$item)
+ {
+ if($index===$editIndex)
+ $style=$editItemStyle;
+ else if($index===$selectedIndex)
+ $style=$selectedItemStyle;
+ else if($index%2===0)
+ $style=$itemStyle;
+ else
+ $style=$alternatingItemStyle;
+ if($style && $item instanceof IStyleable)
+ $item->getStyle()->mergeWith($style);
+ }
+
+ // apply separator style if any
+ if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
+ {
+ $controls=$this->getControls();
+ $count=$controls->getCount();
+ for($i=$this->_header?2:1;$i<$count;$i+=2)
+ {
+ if(($separator=$controls->itemAt($i)) instanceof IStyleable)
+ $separator->getStyle()->mergeWith($separatorStyle);
+ }
+ }
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getIsDataBound())
+ $this->restoreItemsFromViewState();
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Clears up all items in the data list.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ }
+
+ /**
+ * Creates data list items based on viewstate information.
+ */
+ protected function restoreItemsFromViewState()
+ {
+ $this->reset();
+ if(($itemCount=$this->getViewState('ItemCount',0))>0)
+ {
+ $items=$this->getItems();
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $this->_header=$this->createItemInternal(-1,TListItemType::Header);
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($hasSeparator && $i>0)
+ $this->createItemInternal($i-1,TListItemType::Separator);
+ if($i===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($i===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemInternal($i,$itemType));
+ }
+ $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
+ }
+ else
+ $this->createEmptyContent();
+ $this->clearChildState();
+ }
+
+ /**
+ * Performs databinding to populate data list items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+ $itemIndex=0;
+ $items=$this->getItems();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $selectedIndex=$this->getSelectedItemIndex();
+ $editIndex=$this->getEditItemIndex();
+ foreach($data as $key=>$dataItem)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
+ else
+ $keys->add($key);
+ if($itemIndex===0)
+ $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
+ if($hasSeparator && $itemIndex>0)
+ $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
+ if($itemIndex===$editIndex)
+ $itemType=TListItemType::EditItem;
+ else if($itemIndex===$selectedIndex)
+ $itemType=TListItemType::SelectedItem;
+ else
+ $itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
+ $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
+ $itemIndex++;
+ }
+ if($itemIndex>0)
+ $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
+ else
+ {
+ $this->createEmptyContent();
+ $this->dataBindChildren();
+ }
+ $this->setViewState('ItemCount',$itemIndex,0);
+ }
+
+ /**
+ * Renders the data list control.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ if($this->getHasControls())
+ {
+ if($this->getItemCount()>0)
+ {
+ $this->applyItemStyles();
+ $repeatInfo=$this->getRepeatInfo();
+ $repeatInfo->renderRepeater($writer,$this);
+ }
+ else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
+ parent::render($writer);
+ }
+ }
+}
+
+
+/**
+ * TDataListItemEventParameter class
+ *
+ * TDataListItemEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemEventParameter extends TEventParameter
+{
+ /**
+ * The datalist item control responsible for the event.
+ * @var TControl
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TControl DataList item related with the corresponding event
+ */
+ public function __construct($item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TControl datalist item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TDataListCommandEventParameter class
+ *
+ * TDataListCommandEventParameter encapsulates the parameter data for
+ * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
+ *
+ * The {@link getItem Item} property indicates the DataList item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TControl the datalist item control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl datalist item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TControl the datalist item control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TDataListItem class
+ *
+ * A TDataListItem control represents an item in the {@link TDataList} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of DataList
+ */
+ private $_itemIndex;
+ /**
+ * type of the TDataListItem
+ * @var TListItemType
+ */
+ private $_itemType;
+ /**
+ * value of the data associated with this item
+ * @var mixed
+ */
+ private $_data;
+
+ private $_tagName='span';
+
+ /**
+ * Returns the tag name used for this control.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return $this->_tagName;
+ }
+
+ /**
+ * @param string tag name of the control to be rendered
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=$value;
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by a datalist item.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * @return integer zero-based index of the item in the item collection of datalist
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+/**
+ * TDataListItemCollection class.
+ *
+ * TDataListItemCollection represents a collection of data list items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataListItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only TControl descendants.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataListItemRenderer.php b/framework/Web/UI/WebControls/TDataListItemRenderer.php
index 7065dc09..53c48b6e 100644
--- a/framework/Web/UI/WebControls/TDataListItemRenderer.php
+++ b/framework/Web/UI/WebControls/TDataListItemRenderer.php
@@ -1,172 +1,172 @@
-<?php
-/**
- * TDataListItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataListItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataList');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TDataListItemRenderer class
- *
- * TDataListItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TDataList}.
- *
- * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
- * the bubbling scheme for the OnCommand event of data list items.
- *
- * TDataListItemRenderer also implements the {@link IStyleable} interface,
- * which allows TDataList to apply CSS styles to the renders.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
-{
- /**
- * Creates a style object to be used by the control.
- * This method may be overriden by controls to provide customized style.
- * @return TStyle
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return boolean whether the control has defined any style information
- */
- public function getHasStyle()
- {
- return $this->getViewState('Style',null)!==null;
- }
-
- /**
- * @return TStyle the object representing the css style of the control
- */
- public function getStyle()
- {
- if($style=$this->getViewState('Style',null))
- return $style;
- else
- {
- $style=$this->createStyle();
- $this->setViewState('Style',$style,null);
- return $style;
- }
- }
-
- /**
- * Removes all style data.
- */
- public function clearStyle()
- {
- $this->clearViewState('Style');
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-
- /**
- * Returns the tag name used for this control.
- * By default, the tag name is 'span'.
- * You can override this method to provide customized tag names.
- * If the tag name is empty, the opening and closing tag will NOT be rendered.
- * @return string tag name of the control to be rendered
- */
- protected function getTagName()
- {
- return 'span';
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * By default, this method renders the style string.
- * The method can be overriden to provide customized attribute rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- if($style=$this->getViewState('Style',null))
- $style->addAttributesToRender($writer);
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by replacing it with
- * the following sequence:
- * - {@link renderBeginTag}
- * - {@link renderContents}
- * - {@link renderEndTag}
- * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->getTagName()!=='')
- {
- $this->renderBeginTag($writer);
- $this->renderContents($writer);
- $this->renderEndTag($writer);
- }
- else
- $this->renderContents($writer);
- }
-
- /**
- * Renders the openning tag for the control (including attributes)
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- $this->addAttributesToRender($writer);
- $writer->renderBeginTag($this->getTagName());
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * By default, child controls and text strings will be rendered.
- * You can override this method to provide customized content rendering.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- parent::renderChildren($writer);
- }
-
- /**
- * Renders the closing tag for the control
- * This method is invoked when {@link getTagName TagName} is not empty.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- $writer->renderEndTag();
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TDataListItemRenderer class
+ *
+ * TDataListItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TDataList}.
+ *
+ * TDataListItemRenderer extends {@link TItemDataRenderer} and implements
+ * the bubbling scheme for the OnCommand event of data list items.
+ *
+ * TDataListItemRenderer also implements the {@link IStyleable} interface,
+ * which allows TDataList to apply CSS styles to the renders.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TDataListItemRenderer extends TItemDataRenderer implements IStyleable
+{
+ /**
+ * Creates a style object to be used by the control.
+ * This method may be overriden by controls to provide customized style.
+ * @return TStyle
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return boolean whether the control has defined any style information
+ */
+ public function getHasStyle()
+ {
+ return $this->getViewState('Style',null)!==null;
+ }
+
+ /**
+ * @return TStyle the object representing the css style of the control
+ */
+ public function getStyle()
+ {
+ if($style=$this->getViewState('Style',null))
+ return $style;
+ else
+ {
+ $style=$this->createStyle();
+ $this->setViewState('Style',$style,null);
+ return $style;
+ }
+ }
+
+ /**
+ * Removes all style data.
+ */
+ public function clearStyle()
+ {
+ $this->clearViewState('Style');
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns the tag name used for this control.
+ * By default, the tag name is 'span'.
+ * You can override this method to provide customized tag names.
+ * If the tag name is empty, the opening and closing tag will NOT be rendered.
+ * @return string tag name of the control to be rendered
+ */
+ protected function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * By default, this method renders the style string.
+ * The method can be overriden to provide customized attribute rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($style=$this->getViewState('Style',null))
+ $style->addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by replacing it with
+ * the following sequence:
+ * - {@link renderBeginTag}
+ * - {@link renderContents}
+ * - {@link renderEndTag}
+ * If the {@link getTagName TagName} is empty, only {@link renderContents} is invoked.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->getTagName()!=='')
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+ else
+ $this->renderContents($writer);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ $this->addAttributesToRender($writer);
+ $writer->renderBeginTag($this->getTagName());
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * By default, child controls and text strings will be rendered.
+ * You can override this method to provide customized content rendering.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ parent::renderChildren($writer);
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * This method is invoked when {@link getTagName TagName} is not empty.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ $writer->renderEndTag();
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataRenderer.php b/framework/Web/UI/WebControls/TDataRenderer.php
index ece9d974..44ab0b1d 100644
--- a/framework/Web/UI/WebControls/TDataRenderer.php
+++ b/framework/Web/UI/WebControls/TDataRenderer.php
@@ -1,52 +1,52 @@
-<?php
-/**
- * TDataRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-
-/**
- * TDataRenderer class
- *
- * TDataRenderer is the convenient base class for template-based renderer controls.
- * It extends {@link TTemplateControl} and implements the methods required
- * by the {@link IDataRenderer} interface.
- *
- * The following property is provided by TDataRenderer:
- * - {@link getData Data}: data associated with this renderer.
-
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
-{
- /**
- * @var mixed data associated with this renderer
- */
- private $_data;
-
- /**
- * @return mixed data associated with the item
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+
+/**
+ * TDataRenderer class
+ *
+ * TDataRenderer is the convenient base class for template-based renderer controls.
+ * It extends {@link TTemplateControl} and implements the methods required
+ * by the {@link IDataRenderer} interface.
+ *
+ * The following property is provided by TDataRenderer:
+ * - {@link getData Data}: data associated with this renderer.
+
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+abstract class TDataRenderer extends TTemplateControl implements IDataRenderer
+{
+ /**
+ * @var mixed data associated with this renderer
+ */
+ private $_data;
+
+ /**
+ * @return mixed data associated with the item
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataSourceControl.php b/framework/Web/UI/WebControls/TDataSourceControl.php
index 0b07810a..f7a224af 100644
--- a/framework/Web/UI/WebControls/TDataSourceControl.php
+++ b/framework/Web/UI/WebControls/TDataSourceControl.php
@@ -1,118 +1,118 @@
-<?php
-/**
- * IDataSource, TDataSourceControl, TReadOnlyDataSource class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * IDataSource, TDataSourceControl, TReadOnlyDataSource class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * IDataSource class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-interface IDataSource
-{
- public function getView($viewName);
- public function getViewNames();
- public function onDataSourceChanged($param);
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceControl extends TControl implements IDataSource
-{
- public function getView($viewName)
- {
- return null;
- }
-
- public function getViewNames()
- {
- return array();
- }
-
- public function onDataSourceChanged($param)
- {
- $this->raiseEvent('OnDataSourceChanged',$this,$param);
- }
-
- public function focus()
- {
- throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
- }
-
- public function getEnableTheming()
- {
- return false;
- }
-
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
- }
-
- public function getSkinID()
- {
- return '';
- }
-
- public function setSkinID($value)
- {
- throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
- }
-
- public function getVisible($checkParents=true)
- {
- return false;
- }
-
- public function setVisible($value)
- {
- throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
- }
-}
-
-/**
- * TDataSourceControl class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSource extends TDataSourceControl
-{
- private $_dataSource;
- private $_dataMember;
-
- public function __construct($dataSource,$dataMember)
- {
- if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
- throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
- $this->_dataSource=$dataSource;
- $this->_dataMember=$dataMember;
- }
-
- public function getView($viewName)
- {
- if($this->_dataSource instanceof IDataSource)
- return $this->_dataSource->getView($viewName);
- else
- return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * IDataSource class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+interface IDataSource
+{
+ public function getView($viewName);
+ public function getViewNames();
+ public function onDataSourceChanged($param);
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceControl extends TControl implements IDataSource
+{
+ public function getView($viewName)
+ {
+ return null;
+ }
+
+ public function getViewNames()
+ {
+ return array();
+ }
+
+ public function onDataSourceChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceChanged',$this,$param);
+ }
+
+ public function focus()
+ {
+ throw new TNotSupportedException('datasourcecontrol_focus_unsupported');
+ }
+
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_enabletheming_unsupported');
+ }
+
+ public function getSkinID()
+ {
+ return '';
+ }
+
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_skinid_unsupported');
+ }
+
+ public function getVisible($checkParents=true)
+ {
+ return false;
+ }
+
+ public function setVisible($value)
+ {
+ throw new TNotSupportedException('datasourcecontrol_visible_unsupported');
+ }
+}
+
+/**
+ * TDataSourceControl class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSource extends TDataSourceControl
+{
+ private $_dataSource;
+ private $_dataMember;
+
+ public function __construct($dataSource,$dataMember)
+ {
+ if(!is_array($dataSource) && !($dataSource instanceof IDataSource) && !($dataSource instanceof Traversable))
+ throw new TInvalidDataTypeException('readonlydatasource_datasource_invalid');
+ $this->_dataSource=$dataSource;
+ $this->_dataMember=$dataMember;
+ }
+
+ public function getView($viewName)
+ {
+ if($this->_dataSource instanceof IDataSource)
+ return $this->_dataSource->getView($viewName);
+ else
+ return new TReadOnlyDataSourceView($this,$this->_dataMember,$this->_dataSource);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataSourceView.php b/framework/Web/UI/WebControls/TDataSourceView.php
index 9e7c0128..af817a32 100644
--- a/framework/Web/UI/WebControls/TDataSourceView.php
+++ b/framework/Web/UI/WebControls/TDataSourceView.php
@@ -1,206 +1,206 @@
-<?php
-/**
- * TDataSourceSelectParameters, TDataSourceView, TReadOnlyDataSourceView class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataSourceSelectParameters, TDataSourceView, TReadOnlyDataSourceView class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataSourceSelectParameters class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataSourceSelectParameters extends TComponent
-{
- private $_retrieveTotalRowCount=false;
- private $_startRowIndex=0;
- private $_totalRowCount=0;
- private $_maximumRows=0;
-
- public function getStartRowIndex()
- {
- return $this->_startRowIndex;
- }
-
- public function setStartRowIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_startRowIndex=$value;
- }
-
- public function getMaximumRows()
- {
- return $this->_maximumRows;
- }
-
- public function setMaximumRows($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_maximumRows=$value;
- }
-
- public function getRetrieveTotalRowCount()
- {
- return $this->_retrieveTotalRowCount;
- }
-
- public function setRetrieveTotalRowCount($value)
- {
- $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
- }
-
- public function getTotalRowCount()
- {
- return $this->_totalRowCount;
- }
-
- public function setTotalRowCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=0;
- $this->_totalRowCount=$value;
- }
-}
-
-/**
- * TDataSourceView class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TDataSourceView extends TComponent
-{
- private $_owner;
- private $_name;
-
- public function __construct(IDataSource $owner,$viewName)
- {
- $this->_owner=$owner;
- $this->_name=$viewName;
- }
-
- /**
- * Performs DB selection based on specified parameters.
- * @param ???
- * @return Traversable
- */
- abstract public function select($parameters);
-
- /**
- * Inserts a DB record.
- * @param array|TMap
- * @return integer affected rows
- */
- public function insertAt($values)
- {
- throw new TNotSupportedException('datasourceview_insert_unsupported');
- }
-
- /**
- * Updates DB record(s) with the specified keys and new values
- * @param array|TMap keys for specifying the records to be updated
- * @param array|TMap new values
- * @return integer affected rows
- */
- public function update($keys,$values)
- {
- throw new TNotSupportedException('datasourceview_update_unsupported');
- }
-
- /**
- * Deletes DB row(s) with the specified keys.
- * @param array|TMap keys for specifying the rows to be deleted
- * @return integer affected rows
- */
- public function delete($keys)
- {
- throw new TNotSupportedException('datasourceview_delete_unsupported');
- }
-
- public function getCanDelete()
- {
- return false;
- }
-
- public function getCanInsert()
- {
- return false;
- }
-
- public function getCanPage()
- {
- return false;
- }
-
- public function getCanGetRowCount()
- {
- return false;
- }
-
- public function getCanSort()
- {
- return false;
- }
-
- public function getCanUpdate()
- {
- return false;
- }
-
- public function getName()
- {
- return $this->_name;
- }
-
- public function getDataSource()
- {
- return $this->_owner;
- }
-
- public function onDataSourceViewChanged($param)
- {
- $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
- }
-}
-
-/**
- * TReadOnlyDataSourceView class
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TReadOnlyDataSourceView extends TDataSourceView
-{
- private $_dataSource=null;
-
- public function __construct(IDataSource $owner,$viewName,$dataSource)
- {
- parent::__construct($owner,$viewName);
- if($dataSource===null || is_array($dataSource))
- $this->_dataSource=new TMap($dataSource);
- else if($dataSource instanceof Traversable)
- $this->_dataSource=$dataSource;
- else
- throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
- }
-
- public function select($parameters)
- {
- return $this->_dataSource;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataSourceSelectParameters class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataSourceSelectParameters extends TComponent
+{
+ private $_retrieveTotalRowCount=false;
+ private $_startRowIndex=0;
+ private $_totalRowCount=0;
+ private $_maximumRows=0;
+
+ public function getStartRowIndex()
+ {
+ return $this->_startRowIndex;
+ }
+
+ public function setStartRowIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_startRowIndex=$value;
+ }
+
+ public function getMaximumRows()
+ {
+ return $this->_maximumRows;
+ }
+
+ public function setMaximumRows($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_maximumRows=$value;
+ }
+
+ public function getRetrieveTotalRowCount()
+ {
+ return $this->_retrieveTotalRowCount;
+ }
+
+ public function setRetrieveTotalRowCount($value)
+ {
+ $this->_retrieveTotalRowCount=TPropertyValue::ensureBoolean($value);
+ }
+
+ public function getTotalRowCount()
+ {
+ return $this->_totalRowCount;
+ }
+
+ public function setTotalRowCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=0;
+ $this->_totalRowCount=$value;
+ }
+}
+
+/**
+ * TDataSourceView class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TDataSourceView extends TComponent
+{
+ private $_owner;
+ private $_name;
+
+ public function __construct(IDataSource $owner,$viewName)
+ {
+ $this->_owner=$owner;
+ $this->_name=$viewName;
+ }
+
+ /**
+ * Performs DB selection based on specified parameters.
+ * @param ???
+ * @return Traversable
+ */
+ abstract public function select($parameters);
+
+ /**
+ * Inserts a DB record.
+ * @param array|TMap
+ * @return integer affected rows
+ */
+ public function insertAt($values)
+ {
+ throw new TNotSupportedException('datasourceview_insert_unsupported');
+ }
+
+ /**
+ * Updates DB record(s) with the specified keys and new values
+ * @param array|TMap keys for specifying the records to be updated
+ * @param array|TMap new values
+ * @return integer affected rows
+ */
+ public function update($keys,$values)
+ {
+ throw new TNotSupportedException('datasourceview_update_unsupported');
+ }
+
+ /**
+ * Deletes DB row(s) with the specified keys.
+ * @param array|TMap keys for specifying the rows to be deleted
+ * @return integer affected rows
+ */
+ public function delete($keys)
+ {
+ throw new TNotSupportedException('datasourceview_delete_unsupported');
+ }
+
+ public function getCanDelete()
+ {
+ return false;
+ }
+
+ public function getCanInsert()
+ {
+ return false;
+ }
+
+ public function getCanPage()
+ {
+ return false;
+ }
+
+ public function getCanGetRowCount()
+ {
+ return false;
+ }
+
+ public function getCanSort()
+ {
+ return false;
+ }
+
+ public function getCanUpdate()
+ {
+ return false;
+ }
+
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ public function getDataSource()
+ {
+ return $this->_owner;
+ }
+
+ public function onDataSourceViewChanged($param)
+ {
+ $this->raiseEvent('OnDataSourceViewChanged',$this,$param);
+ }
+}
+
+/**
+ * TReadOnlyDataSourceView class
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TReadOnlyDataSourceView extends TDataSourceView
+{
+ private $_dataSource=null;
+
+ public function __construct(IDataSource $owner,$viewName,$dataSource)
+ {
+ parent::__construct($owner,$viewName);
+ if($dataSource===null || is_array($dataSource))
+ $this->_dataSource=new TMap($dataSource);
+ else if($dataSource instanceof Traversable)
+ $this->_dataSource=$dataSource;
+ else
+ throw new TInvalidDataTypeException('readonlydatasourceview_datasource_invalid');
+ }
+
+ public function select($parameters)
+ {
+ return $this->_dataSource;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php
index 24372565..0e412e24 100644
--- a/framework/Web/UI/WebControls/TDataTypeValidator.php
+++ b/framework/Web/UI/WebControls/TDataTypeValidator.php
@@ -1,141 +1,141 @@
-<?php
-/**
- * TDataTypeValidator class.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDataTypeValidator class.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TDataTypeValidator class
- *
- * TDataTypeValidator verifies if the input data is of the type specified
- * by {@link setDataType DataType}.
- * The following data types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type.
- * - <b>String</b> A string data type.
- * For <b>Date</b> type, the property {@link setDateFormat DateFormat}
- * will be used to determine how to parse the date string. If it is not
- * provided, the string will be assumed to be in GNU datetime format.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDataTypeValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDataTypeValidator';
- }
-
- /**
- * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType','String');
- }
-
- /**
- * Sets the data type that the values being compared are converted to before the comparison is made.
- * @param TValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
-
- /**
- * Determine if the given value is of a particular type using RegExp.
- * @param string value to check
- * @return boolean true if value fits the type expression.
- */
- protected function evaluateDataTypeCheck($value)
- {
- if($value=='')
- return true;
-
- switch($this->getDataType())
- {
- case TValidationDataType::Integer:
- return preg_match('/^[-+]?[0-9]+$/',trim($value));
- case TValidationDataType::Float:
- return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
- case TValidationDataType::Date:
- $dateFormat = $this->getDateFormat();
- if(strlen($dateFormat))
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
- return $formatter->isValidDate($value);
- }
- else
- return strtotime($value) > 0;
- }
- return true;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['DataType']=$this->getDataType();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data is of valid type.
- * The validation always succeeds if ControlToValidate is not specified
- * or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
-
- return $this->evaluateDataTypeCheck($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TDataTypeValidator class
+ *
+ * TDataTypeValidator verifies if the input data is of the type specified
+ * by {@link setDataType DataType}.
+ * The following data types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type.
+ * - <b>String</b> A string data type.
+ * For <b>Date</b> type, the property {@link setDateFormat DateFormat}
+ * will be used to determine how to parse the date string. If it is not
+ * provided, the string will be assumed to be in GNU datetime format.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDataTypeValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDataTypeValidator';
+ }
+
+ /**
+ * @return TValidationDataType the data type that the values being compared are converted to before the comparison is made. Defaults to TValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType','String');
+ }
+
+ /**
+ * Sets the data type that the values being compared are converted to before the comparison is made.
+ * @param TValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TValidationDataType'),TValidationDataType::String);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+
+ /**
+ * Determine if the given value is of a particular type using RegExp.
+ * @param string value to check
+ * @return boolean true if value fits the type expression.
+ */
+ protected function evaluateDataTypeCheck($value)
+ {
+ if($value=='')
+ return true;
+
+ switch($this->getDataType())
+ {
+ case TValidationDataType::Integer:
+ return preg_match('/^[-+]?[0-9]+$/',trim($value));
+ case TValidationDataType::Float:
+ return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
+ case TValidationDataType::Date:
+ $dateFormat = $this->getDateFormat();
+ if(strlen($dateFormat))
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$dateFormat);
+ return $formatter->isValidDate($value);
+ }
+ else
+ return strtotime($value) > 0;
+ }
+ return true;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['DataType']=$this->getDataType();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data is of valid type.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+
+ return $this->evaluateDataTypeCheck($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php
index 8d1a811c..866bc585 100644
--- a/framework/Web/UI/WebControls/TDatePicker.php
+++ b/framework/Web/UI/WebControls/TDatePicker.php
@@ -1,993 +1,993 @@
-<?php
-/**
- * TDatePicker class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTextBox class
- */
-Prado::using('System.Web.UI.WebControls.TTextBox');
-
-/**
- *
- * TDatePicker class.
- *
- * TDatePicker displays a text box for date input purpose.
- * When the text box receives focus, a calendar will pop up and users can
- * pick up from it a date that will be automatically entered into the text box.
- * The format of the date string displayed in the text box is determined by
- * the <b>DateFormat</b> property. Valid formats are the combination of the
- * following tokens,
- *
- * <code>
- * Character Format Pattern (en-US)
- * -----------------------------------------
- * d day digit
- * dd padded day digit e.g. 01, 02
- * M month digit
- * MM padded month digit
- * MMMM localized month name, e.g. March, April
- * yy 2 digit year
- * yyyy 4 digit year
- * -----------------------------------------
- * </code>
- *
- * TDatePicker has four <b>Mode</b> to show the date picker popup.
- *
- * # <b>Basic</b> -- Only shows a text input, focusing on the input shows the
- * date picker. This way you can access the popup using only
- * the keyboard. Note that because of this, TAB-bing through
- * this control will automatically select the current date if
- * no previous date was selected. If you close the popup (eg.
- * pressing the ESC key) you'll need to un-focus and re-focus
- * the control again for the popup to reappear.
- * # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the
- * date picker. This mode solves the two small problems of the
- * Basic mode. It was first introduced in Prado 3.2.
- * # <b>Button</b> -- Shows a button next to the text input, clicking on the
- * button shows the date, button text can be by the
- * <b>ButtonText</b> property
- * # <b>ImageButton</b> -- Shows an image next to the text input, clicking on
- * the image shows the date picker, image source can be
- * change through the <b>ButtonImageUrl</b> property.
- *
- * The <b>CssClass</b> property can be used to override the css class name
- * for the date picker panel. <b>CalendarStyle</b> property sets the packages
- * styles available. E.g. <b>default</b>.
- *
- * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with
- * default as "TextBox".
- * In <b>DropDownList</b> mode, in addition to the popup date picker, three
- * drop down list (day, month and year) are presented to select the date .
- *
- * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default
- * as "Bottom". It specifies the position of the calendar popup, relative to the
- * input field.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Carl G. Mathisen <carlgmathisen@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDatePicker extends TTextBox
-{
- /**
- * Script path relative to the TClientScriptManager::SCRIPT_PATH
- */
- const SCRIPT_PATH = 'prado/datepicker';
-
- /**
- * @var TDatePickerClientScript validator client-script options.
- */
- private $_clientScript;
- /**
- * AutoPostBack is not supported.
- */
- public function setAutoPostBack($value)
- {
- throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
- get_class($this));
- }
-
- /**
- * @return string the format of the date string
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat','dd-MM-yyyy');
- }
-
- /**
- * Sets the format of the date string.
- * @param string the format of the date string
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
- }
-
- /**
- * @return boolean whether the calendar window should pop up when the control receives focus
- */
- public function getShowCalendar()
- {
- return $this->getViewState('ShowCalendar',true);
- }
-
- /**
- * Sets whether to pop up the calendar window when the control receives focus
- * @param boolean whether to show the calendar window
- */
- public function setShowCalendar($value)
- {
- $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Gets the current culture.
- * @return string current culture, e.g. en_AU.
- */
- public function getCulture()
- {
- return $this->getViewState('Culture', '');
- }
-
- /**
- * Sets the culture/language for the date picker.
- * @param string a culture string, e.g. en_AU.
- */
- public function setCulture($value)
- {
- $this->setViewState('Culture', $value, '');
- }
-
- /**
- * @param TDatePickerInputMode input method of date values
- */
- public function setInputMode($value)
- {
- $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
- }
-
- /**
- * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
- */
- public function getInputMode()
- {
- return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
- }
-
- /**
- * @param TDatePickerMode calendar UI mode
- */
- public function setMode($value)
- {
- $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
- }
-
- /**
- * @return TDatePickerMode current calendar UI mode.
- */
- public function getMode()
- {
- return $this->getViewState('Mode', TDatePickerMode::Basic);
- }
- /**
- * @param string the image url for "Image" UI mode.
- */
- public function setButtonImageUrl($value)
- {
- $this->setViewState('ImageUrl', $value, '');
- }
-
- /**
- * @return string the image url for "Image" UI mode.
- */
- public function getButtonImageUrl()
- {
- return $this->getViewState('ImageUrl', '');
- }
-
- /**
- * @param string set the calendar style
- */
- public function setCalendarStyle($value)
- {
- $this->setViewState('CalendarStyle', $value, 'default');
- }
-
- /**
- * @return string current calendar style
- */
- public function getCalendarStyle()
- {
- return $this->getViewState('CalendarStyle', 'default');
- }
-
- /**
- * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
- * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
- */
- public function setFirstDayOfWeek($value)
- {
- $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
- }
-
- /**
- * @return integer first day of the week
- */
- public function getFirstDayOfWeek()
- {
- return $this->getViewState('FirstDayOfWeek', 1);
- }
-
- /**
- * @return string text for the date picker button. Default is "...".
- */
- public function getButtonText()
- {
- return $this->getViewState('ButtonText', '...');
- }
-
- /**
- * @param string text for the date picker button
- */
- public function setButtonText($value)
- {
- $this->setViewState('ButtonText', $value, '...');
- }
-
- /**
- * @param integer date picker starting year, default is 2000.
- */
- public function setFromYear($value)
- {
- $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
- }
-
- /**
- * @return integer date picker starting year, default is -5 years
- */
- public function getFromYear()
- {
- return $this->getViewState('FromYear', intval(@date('Y'))-5);
- }
-
- /**
- * @param integer date picker ending year, default +10 years
- */
- public function setUpToYear($value)
- {
- $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
- }
-
- /**
- * @return integer date picker ending year, default +10 years
- */
- public function getUpToYear()
- {
- return $this->getViewState('UpToYear', intval(@date('Y'))+10);
- }
-
- /**
- * @param TDatePickerPositionMode calendar UI position
- */
- public function setPositionMode($value)
- {
- $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return TDatePickerPositionMode current calendar UI position.
- */
- public function getPositionMode()
- {
- return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
- }
-
- /**
- * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
- */
- public function getTimeStamp()
- {
- if(trim($this->getText())==='')
- return null;
- else
- return $this->getTimeStampFromText();
- }
-
- /**
- * Sets the date for the date picker using timestamp.
- * @param float time stamp for the date picker
- */
- public function setTimeStamp($value)
- {
- if($value===null || (is_string($value) && trim($value)===''))
- $this->setText('');
- else
- {
- $date = TPropertyValue::ensureFloat($value);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
- $this->setText($formatter->format($date));
- }
- }
-
- /**
- * Returns the timestamp selected by the user.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getTimeStamp()}.
- * @return integer the timestamp of the TDatePicker control.
- * @see getTimeStamp
- * @since 3.1.2
- */
- public function getData()
- {
- return $this->getTimeStamp();
- }
-
- /**
- * Sets the timestamp represented by this control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setTimeStamp()}.
- * @param integer the timestamp of the TDatePicker control.
- * @see setTimeStamp
- * @since 3.1.2
- */
- public function setData($value)
- {
- $this->setTimeStamp($value);
- }
-
- /**
- * @return string the date string.
- */
- public function getDate()
- {
- return $this->getText();
- }
-
- /**
- * @param string date string
- */
- public function setDate($value)
- {
- $this->setText($value);
- }
-
- /**
- * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
- *
- * The date picker on the client-side supports the following events.
- * # <tt>OnDateChanged</tt> -- raised when the date is changed.
- *
- * You can attach custom javascript code to each of these events
- *
- * @return TDatePickerClientScript javascript validator event options.
- */
- public function getClientSide()
- {
- if($this->_clientScript===null)
- $this->_clientScript = $this->createClientScript();
- return $this->_clientScript;
- }
-
- /**
- * @return TDatePickerClientScript javascript validator event options.
- */
- protected function createClientScript()
- {
- return new TDatePickerClientScript;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return integer the interger timestamp if valid, otherwise the original text.
- */
- public function getValidationPropertyValue()
- {
- if(($text = $this->getText()) === '')
- return '';
- $date = $this->getTimeStamp();
- return $date == null ? $text : $date;
- }
-
- /**
- * Publish the date picker Css asset files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getInputMode() === TDatePickerInputMode::DropDownList)
- {
- $page = $this->getPage();
- $uniqueID = $this->getUniqueID();
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month');
- $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year');
- }
- $this->publishCalendarStyle();
- $this->registerCalendarClientScriptPre();
- }
-
- /**
- * Renders body content.
- * This method overrides parent implementation by adding
- * additional date picker button if Mode is Button or ImageButton.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- {
- parent::render($writer);
- $this->renderDatePickerButtons($writer);
- }
- else
- {
- $this->renderDropDownListCalendar($writer);
- if($this->hasDayPattern())
- {
- $this->registerCalendarClientScriptPost();
- $this->renderDatePickerButtons($writer);
- }
- }
- }
-
- /**
- * Renders the date picker popup buttons.
- */
- protected function renderDatePickerButtons($writer)
- {
- if($this->getShowCalendar())
- {
- switch ($this->getMode())
- {
- case TDatePickerMode::Button:
- $this->renderButtonDatePicker($writer);
- break;
- case TDatePickerMode::ImageButton :
- $this->renderImageButtonDatePicker($writer);
- break;
- }
- }
- }
-
- /**
- * Loads user input data. Override parent implementation, when InputMode
- * is DropDownList call getDateFromPostData to get date data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if($this->getInputMode() == TDatePickerInputMode::TextBox)
- return parent::loadPostData($key, $values);
- $value = $this->getDateFromPostData($key, $values);
- if(!$this->getReadOnly() && $this->getText()!==$value)
- {
- $this->setText($value);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Loads date from drop down list data.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return array the date selected
- */
- protected function getDateFromPostData($key, $values)
- {
- $date = @getdate();
-
- if(isset($values[$key.'$day']))
- $day = intval($values[$key.'$day']);
- else
- $day = $date['mday'];
-
- if(isset($values[$key.'$month']))
- $month = intval($values[$key.'$month']) + 1;
- else
- $month = $date['mon'];
-
- if(isset($values[$key.'$year']))
- $year = intval($values[$key.'$year']);
- else
- $year = $date['year'];
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
- //$date = @mktime(0, 0, 0, $month, $day, $year);
-
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
- return $formatter->format($date);
- }
-
- /**
- * Get javascript date picker options.
- * @return array date picker client-side options
- */
- protected function getDatePickerOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['InputMode'] = $this->getInputMode();
- $options['Format'] = $this->getDateFormat();
- $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
- if(($cssClass=$this->getCssClass())!=='')
- $options['ClassName'] = $cssClass;
- $options['CalendarStyle'] = $this->getCalendarStyle();
- $options['FromYear'] = $this->getFromYear();
- $options['UpToYear'] = $this->getUpToYear();
- switch($this->getMode())
- {
- case TDatePickerMode::Basic:
- break;
- case TDatePickerMode::Clickable:
- $options['TriggerEvent'] = "click";
- break;
- default:
- $options['Trigger'] = $this->getDatePickerButtonID();
- break;
- }
- $options['PositionMode'] = $this->getPositionMode();
-
- $options = array_merge($options, $this->getCulturalOptions());
- if($this->_clientScript!==null)
- $options = array_merge($options,
- $this->_clientScript->getOptions()->toArray());
- return $options;
- }
-
- /**
- * Get javascript localization options, e.g. month and weekday names.
- * @return array localization options.
- */
- protected function getCulturalOptions()
- {
- if($this->getCurrentCulture() == 'en')
- return array();
-
- $date = $this->getLocalizedCalendarInfo();
- $options['MonthNames'] = $date->getMonthNames();
- $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
- $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
-
- return $options;
- }
-
- /**
- * @return string the current culture, falls back to application if culture is not set.
- */
- protected function getCurrentCulture()
- {
- $app = $this->getApplication()->getGlobalization(false);
- return $this->getCulture() == '' ?
- ($app ? $app->getCulture() : 'en') : $this->getCulture();
- }
-
- /**
- * @return DateTimeFormatInfo date time format information for the current culture.
- */
- protected function getLocalizedCalendarInfo()
- {
- //expensive operations
- $culture = $this->getCurrentCulture();
- Prado::using('System.I18N.core.DateTimeFormatInfo');
- $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
- return $info->getDateTimeFormat();
- }
-
- /**
- * Renders the drop down list date picker.
- */
- protected function renderDropDownListCalendar($writer)
- {
- if($this->getMode() == TDatePickerMode::Basic)
- $this->setMode(TDatePickerMode::ImageButton);
- parent::addAttributesToRender($writer);
- $writer->removeAttribute('name');
- $writer->removeAttribute('type');
- $writer->addAttribute('id', $this->getClientID());
-
- if(strlen($class = $this->getCssClass()) > 0)
- $writer->addAttribute('class', $class);
- $writer->renderBeginTag('span');
-
- $s = Prado::createComponent('System.Util.TDateTimeStamp');
- $date = $s->getDate($this->getTimeStampFromText());
- //$date = @getdate($this->getTimeStampFromText());
-
- $this->renderCalendarSelections($writer, $date);
-
- //render a hidden input field
- $writer->addAttribute('name', $this->getUniqueID());
- $writer->addAttribute('type', 'hidden');
- $writer->addAttribute('value', $this->getText());
- $writer->renderBeginTag('input');
-
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
-
- protected function hasDayPattern()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- return ($formatter->getDayPattern()!==null);
- }
-
- /**
- * Renders the calendar drop down list depending on the DateFormat pattern.
- * @param THtmlWriter the Html writer to render the drop down lists.
- * @param array the current selected date
- */
- protected function renderCalendarSelections($writer, $date)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
-
- foreach($formatter->getDayMonthYearOrdering() as $type)
- {
- if($type == 'day')
- $this->renderCalendarDayOptions($writer,$date['mday']);
- elseif($type == 'month')
- $this->renderCalendarMonthOptions($writer,$date['mon']);
- elseif($type == 'year')
- $this->renderCalendarYearOptions($writer,$date['year']);
- }
- }
-
- /**
- * Gets the date from the text input using TSimpleDateFormatter
- * @return integer current selected date timestamp
- */
- protected function getTimeStampFromText()
- {
- $pattern = $this->getDateFormat();
- $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
- return $formatter->parse($this->getText());
- }
-
- /**
- * Renders a drop down lists.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param array list of selection options
- * @param mixed selected key.
- */
- private function renderDropDownListOptions($writer,$options,$selected=null)
- {
- foreach($options as $k => $v)
- {
- $writer->addAttribute('value', $k);
- if($k == $selected)
- $writer->addAttribute('selected', 'selected');
- $writer->renderBeginTag('option');
- $writer->write($v);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the day drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected day.
- */
- protected function renderCalendarDayOptions($writer, $selected=null)
- {
- $days = $this->getDropDownDayOptions();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
- $writer->addAttribute('class', 'datepicker_day_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer, $days, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * @return array list of day options for a drop down list.
- */
- protected function getDropDownDayOptions()
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- $days = array();
- $requiresPadding = $formatter->getDayPattern() === 'dd';
- for($i=1;$i<=31;$i++)
- {
- $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
- }
- return $days;
- }
-
- /**
- * Renders the month drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected month.
- */
- protected function renderCalendarMonthOptions($writer, $selected=null)
- {
- $info = $this->getLocalizedCalendarInfo();
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
- $writer->addAttribute('class', 'datepicker_month_options');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $this->renderDropDownListOptions($writer,
- $this->getLocalizedMonthNames($info), $selected-1);
- $writer->renderEndTag();
- }
-
- /**
- * Returns the localized month names that depends on the month format pattern.
- * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
- * and "M" return month digits.
- * @param DateTimeFormatInfo localized date format information.
- * @return array localized month names.
- */
- protected function getLocalizedMonthNames($info)
- {
- $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
- $this->getDateFormat());
- switch($formatter->getMonthPattern())
- {
- case 'MMM': return $info->getAbbreviatedMonthNames();
- case 'MM':
- $array = array();
- for($i=1;$i<=12;$i++)
- $array[$i-1] = $i < 10 ? '0'.$i : $i;
- return $array;
- case 'M':
- $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
- return $array;
- default : return $info->getMonthNames();
- }
- }
-
- /**
- * Renders the year drop down list options.
- * @param THtmlWriter the writer used for the rendering purpose
- * @param mixed selected year.
- */
- protected function renderCalendarYearOptions($writer, $selected=null)
- {
- $years = array();
- for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
- $years[$i] = $i;
- $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
- $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
- if($this->getReadOnly() || !$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag('select');
- $writer->addAttribute('class', 'datepicker_year_options');
- $this->renderDropDownListOptions($writer, $years, $selected);
- $writer->renderEndTag();
- }
-
- /**
- * Gets the ID for the date picker trigger button.
- * @return string unique button ID
- */
- protected function getDatePickerButtonID()
- {
- return $this->getClientID().'button';
- }
-
- /**
- * Adds an additional button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderButtonDatePicker($writer)
- {
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('type', 'button');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
- $writer->addAttribute('value',$this->getButtonText());
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->renderBeginTag("input");
- $writer->renderEndTag();
- }
-
- /**
- * Adds an additional image button such that when clicked it shows the date picker.
- * @return THtmlWriter writer
- */
- protected function renderImageButtonDatePicker($writer)
- {
- $url = $this->getButtonImageUrl();
- $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
- $writer->addAttribute('id', $this->getDatePickerButtonID());
- $writer->addAttribute('src', $url);
- $writer->addAttribute('alt', ' ');
- $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled', 'disabled');
- $writer->addAttribute('type', 'image');
- $writer->addAttribute('onclick', 'return false;');
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * @param string date picker asset file in the self::SCRIPT_PATH directory.
- * @return string date picker asset url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Publish the calendar style Css asset file.
- * @return string Css file url.
- */
- protected function publishCalendarStyle()
- {
- $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- return $url;
- }
-
- /**
- * Add the client id to the input textbox, and register the client scripts.
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- $this->registerCalendarClientScriptPost();
- }
-
-
- /**
- * Registers the javascript code to initialize the date picker.
- */
- protected function registerCalendarClientScriptPre()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPradoScript("datepicker");
- }
- }
-
- protected function registerCalendarClientScriptPost()
- {
- if($this->getShowCalendar())
- {
- $cs = $this->getPage()->getClientScript();
- if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
- {
- $spacer = $this->getAssetUrl('spacer.gif');
- $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
- $cs->registerEndScript('TDatePicker.spacer', $code);
- }
-
- $options = TJavaScript::encode($this->getDatePickerOptions());
- $code = "new Prado.WebUI.TDatePicker($options);";
- $cs->registerEndScript("prado:".$this->getClientID(), $code);
- }
- }
-}
-
-/**
- * TDatePickerClientScript class.
- *
- * Client-side date picker event {@link setOnDateChanged OnDateChanged}
- * can be modified through the {@link TDatePicker::getClientSide ClientSide}
- * property of a date picker.
- *
- * The <tt>OnDateChanged</tt> event is raise when the date picker's date
- * is changed.
- * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
- * as parameter to this event
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerClientScript extends TClientSideOptions
-{
- /**
- * Javascript code to execute when the date picker's date is changed.
- * @param string javascript code
- */
- public function setOnDateChanged($javascript)
- {
- $this->setFunction('OnDateChanged', $javascript);
- }
-
- /**
- * @return string javascript code to execute when the date picker's date is changed.
- */
- public function getOnDateChanged()
- {
- return $this->getOption('OnDateChanged');
- }
-}
-
-
-/**
- * TDatePickerInputMode class.
- * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
- *
- * The following enumerable values are defined:
- * - TextBox: text boxes are used to input date values
- * - DropDownList: dropdown lists are used to pick up date values
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerInputMode extends TEnumerable
-{
- const TextBox='TextBox';
- const DropDownList='DropDownList';
-}
-
-/**
- * TDatePickerMode class.
- * TDatePickerMode defines the enumerable type for the possible UI mode
- * that a {@link TDatePicker} control can take.
- *
- * The following enumerable values are defined:
- * - Basic: Only shows a text input, focusing on the input shows the date picker
- * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
- * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
- * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDatePickerMode extends TEnumerable
-{
- const Basic='Basic';
- const Clickable='Clickable';
- const Button='Button';
- const ImageButton='ImageButton';
-}
-
-/**
- * TDatePickerPositionMode class.
- * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
- *
- * The following enumerable values are defined:
- * - Top: the date picker is placed above the input field
- * - Bottom: the date picker is placed below the input field
- *
- * @author Carl G. Mathisen <carlgmathisen@gmail.com>
- * @package System.Web.UI.WebControls
- * @since 3.1.4
- */
-class TDatePickerPositionMode extends TEnumerable
-{
- const Top='Top';
- const Bottom='Bottom';
-}
+<?php
+/**
+ * TDatePicker class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTextBox class
+ */
+Prado::using('System.Web.UI.WebControls.TTextBox');
+
+/**
+ *
+ * TDatePicker class.
+ *
+ * TDatePicker displays a text box for date input purpose.
+ * When the text box receives focus, a calendar will pop up and users can
+ * pick up from it a date that will be automatically entered into the text box.
+ * The format of the date string displayed in the text box is determined by
+ * the <b>DateFormat</b> property. Valid formats are the combination of the
+ * following tokens,
+ *
+ * <code>
+ * Character Format Pattern (en-US)
+ * -----------------------------------------
+ * d day digit
+ * dd padded day digit e.g. 01, 02
+ * M month digit
+ * MM padded month digit
+ * MMMM localized month name, e.g. March, April
+ * yy 2 digit year
+ * yyyy 4 digit year
+ * -----------------------------------------
+ * </code>
+ *
+ * TDatePicker has four <b>Mode</b> to show the date picker popup.
+ *
+ * # <b>Basic</b> -- Only shows a text input, focusing on the input shows the
+ * date picker. This way you can access the popup using only
+ * the keyboard. Note that because of this, TAB-bing through
+ * this control will automatically select the current date if
+ * no previous date was selected. If you close the popup (eg.
+ * pressing the ESC key) you'll need to un-focus and re-focus
+ * the control again for the popup to reappear.
+ * # <b>Clickable</b> -- Only shows a text input, clicking on the input shows the
+ * date picker. This mode solves the two small problems of the
+ * Basic mode. It was first introduced in Prado 3.2.
+ * # <b>Button</b> -- Shows a button next to the text input, clicking on the
+ * button shows the date, button text can be by the
+ * <b>ButtonText</b> property
+ * # <b>ImageButton</b> -- Shows an image next to the text input, clicking on
+ * the image shows the date picker, image source can be
+ * change through the <b>ButtonImageUrl</b> property.
+ *
+ * The <b>CssClass</b> property can be used to override the css class name
+ * for the date picker panel. <b>CalendarStyle</b> property sets the packages
+ * styles available. E.g. <b>default</b>.
+ *
+ * The <b>InputMode</b> property can be set to "TextBox" or "DropDownList" with
+ * default as "TextBox".
+ * In <b>DropDownList</b> mode, in addition to the popup date picker, three
+ * drop down list (day, month and year) are presented to select the date .
+ *
+ * The <b>PositionMode</b> property can be set to "Top" or "Bottom" with default
+ * as "Bottom". It specifies the position of the calendar popup, relative to the
+ * input field.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDatePicker extends TTextBox
+{
+ /**
+ * Script path relative to the TClientScriptManager::SCRIPT_PATH
+ */
+ const SCRIPT_PATH = 'prado/datepicker';
+
+ /**
+ * @var TDatePickerClientScript validator client-script options.
+ */
+ private $_clientScript;
+ /**
+ * AutoPostBack is not supported.
+ */
+ public function setAutoPostBack($value)
+ {
+ throw new TNotSupportedException('tdatepicker_autopostback_unsupported',
+ get_class($this));
+ }
+
+ /**
+ * @return string the format of the date string
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat','dd-MM-yyyy');
+ }
+
+ /**
+ * Sets the format of the date string.
+ * @param string the format of the date string
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat',$value,'dd-MM-yyyy');
+ }
+
+ /**
+ * @return boolean whether the calendar window should pop up when the control receives focus
+ */
+ public function getShowCalendar()
+ {
+ return $this->getViewState('ShowCalendar',true);
+ }
+
+ /**
+ * Sets whether to pop up the calendar window when the control receives focus
+ * @param boolean whether to show the calendar window
+ */
+ public function setShowCalendar($value)
+ {
+ $this->setViewState('ShowCalendar',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Gets the current culture.
+ * @return string current culture, e.g. en_AU.
+ */
+ public function getCulture()
+ {
+ return $this->getViewState('Culture', '');
+ }
+
+ /**
+ * Sets the culture/language for the date picker.
+ * @param string a culture string, e.g. en_AU.
+ */
+ public function setCulture($value)
+ {
+ $this->setViewState('Culture', $value, '');
+ }
+
+ /**
+ * @param TDatePickerInputMode input method of date values
+ */
+ public function setInputMode($value)
+ {
+ $this->setViewState('InputMode', TPropertyValue::ensureEnum($value, 'TDatePickerInputMode'), TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @return TDatePickerInputMode input method of date values. Defaults to TDatePickerInputMode::TextBox.
+ */
+ public function getInputMode()
+ {
+ return $this->getViewState('InputMode', TDatePickerInputMode::TextBox);
+ }
+
+ /**
+ * @param TDatePickerMode calendar UI mode
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode', TPropertyValue::ensureEnum($value, 'TDatePickerMode'), TDatePickerMode::Basic);
+ }
+
+ /**
+ * @return TDatePickerMode current calendar UI mode.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode', TDatePickerMode::Basic);
+ }
+ /**
+ * @param string the image url for "Image" UI mode.
+ */
+ public function setButtonImageUrl($value)
+ {
+ $this->setViewState('ImageUrl', $value, '');
+ }
+
+ /**
+ * @return string the image url for "Image" UI mode.
+ */
+ public function getButtonImageUrl()
+ {
+ return $this->getViewState('ImageUrl', '');
+ }
+
+ /**
+ * @param string set the calendar style
+ */
+ public function setCalendarStyle($value)
+ {
+ $this->setViewState('CalendarStyle', $value, 'default');
+ }
+
+ /**
+ * @return string current calendar style
+ */
+ public function getCalendarStyle()
+ {
+ return $this->getViewState('CalendarStyle', 'default');
+ }
+
+ /**
+ * Set the first day of week, with 0 as Sunday, 1 as Monday, etc.
+ * @param integer 0 for Sunday, 1 for Monday, 2 for Tuesday, etc.
+ */
+ public function setFirstDayOfWeek($value)
+ {
+ $this->setViewState('FirstDayOfWeek', TPropertyValue::ensureInteger($value), 1);
+ }
+
+ /**
+ * @return integer first day of the week
+ */
+ public function getFirstDayOfWeek()
+ {
+ return $this->getViewState('FirstDayOfWeek', 1);
+ }
+
+ /**
+ * @return string text for the date picker button. Default is "...".
+ */
+ public function getButtonText()
+ {
+ return $this->getViewState('ButtonText', '...');
+ }
+
+ /**
+ * @param string text for the date picker button
+ */
+ public function setButtonText($value)
+ {
+ $this->setViewState('ButtonText', $value, '...');
+ }
+
+ /**
+ * @param integer date picker starting year, default is 2000.
+ */
+ public function setFromYear($value)
+ {
+ $this->setViewState('FromYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))-5);
+ }
+
+ /**
+ * @return integer date picker starting year, default is -5 years
+ */
+ public function getFromYear()
+ {
+ return $this->getViewState('FromYear', intval(@date('Y'))-5);
+ }
+
+ /**
+ * @param integer date picker ending year, default +10 years
+ */
+ public function setUpToYear($value)
+ {
+ $this->setViewState('UpToYear', TPropertyValue::ensureInteger($value), intval(@date('Y'))+10);
+ }
+
+ /**
+ * @return integer date picker ending year, default +10 years
+ */
+ public function getUpToYear()
+ {
+ return $this->getViewState('UpToYear', intval(@date('Y'))+10);
+ }
+
+ /**
+ * @param TDatePickerPositionMode calendar UI position
+ */
+ public function setPositionMode($value)
+ {
+ $this->setViewState('PositionMode', TPropertyValue::ensureEnum($value, 'TDatePickerPositionMode'), TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return TDatePickerPositionMode current calendar UI position.
+ */
+ public function getPositionMode()
+ {
+ return $this->getViewState('PositionMode', TDatePickerPositionMode::Bottom);
+ }
+
+ /**
+ * @return integer current selected date from the date picker as timestamp, NULL if timestamp is not set previously.
+ */
+ public function getTimeStamp()
+ {
+ if(trim($this->getText())==='')
+ return null;
+ else
+ return $this->getTimeStampFromText();
+ }
+
+ /**
+ * Sets the date for the date picker using timestamp.
+ * @param float time stamp for the date picker
+ */
+ public function setTimeStamp($value)
+ {
+ if($value===null || (is_string($value) && trim($value)===''))
+ $this->setText('');
+ else
+ {
+ $date = TPropertyValue::ensureFloat($value);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$this->getDateFormat());
+ $this->setText($formatter->format($date));
+ }
+ }
+
+ /**
+ * Returns the timestamp selected by the user.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getTimeStamp()}.
+ * @return integer the timestamp of the TDatePicker control.
+ * @see getTimeStamp
+ * @since 3.1.2
+ */
+ public function getData()
+ {
+ return $this->getTimeStamp();
+ }
+
+ /**
+ * Sets the timestamp represented by this control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setTimeStamp()}.
+ * @param integer the timestamp of the TDatePicker control.
+ * @see setTimeStamp
+ * @since 3.1.2
+ */
+ public function setData($value)
+ {
+ $this->setTimeStamp($value);
+ }
+
+ /**
+ * @return string the date string.
+ */
+ public function getDate()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * @param string date string
+ */
+ public function setDate($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * Gets the TDatePickerClientScript to set the TDatePicker event handlers.
+ *
+ * The date picker on the client-side supports the following events.
+ * # <tt>OnDateChanged</tt> -- raised when the date is changed.
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientScript===null)
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TDatePickerClientScript javascript validator event options.
+ */
+ protected function createClientScript()
+ {
+ return new TDatePickerClientScript;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return integer the interger timestamp if valid, otherwise the original text.
+ */
+ public function getValidationPropertyValue()
+ {
+ if(($text = $this->getText()) === '')
+ return '';
+ $date = $this->getTimeStamp();
+ return $date == null ? $text : $date;
+ }
+
+ /**
+ * Publish the date picker Css asset files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getInputMode() === TDatePickerInputMode::DropDownList)
+ {
+ $page = $this->getPage();
+ $uniqueID = $this->getUniqueID();
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'day');
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'month');
+ $page->registerPostDataLoader($uniqueID.TControl::ID_SEPARATOR.'year');
+ }
+ $this->publishCalendarStyle();
+ $this->registerCalendarClientScriptPre();
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by adding
+ * additional date picker button if Mode is Button or ImageButton.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ {
+ parent::render($writer);
+ $this->renderDatePickerButtons($writer);
+ }
+ else
+ {
+ $this->renderDropDownListCalendar($writer);
+ if($this->hasDayPattern())
+ {
+ $this->registerCalendarClientScriptPost();
+ $this->renderDatePickerButtons($writer);
+ }
+ }
+ }
+
+ /**
+ * Renders the date picker popup buttons.
+ */
+ protected function renderDatePickerButtons($writer)
+ {
+ if($this->getShowCalendar())
+ {
+ switch ($this->getMode())
+ {
+ case TDatePickerMode::Button:
+ $this->renderButtonDatePicker($writer);
+ break;
+ case TDatePickerMode::ImageButton :
+ $this->renderImageButtonDatePicker($writer);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Loads user input data. Override parent implementation, when InputMode
+ * is DropDownList call getDateFromPostData to get date data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if($this->getInputMode() == TDatePickerInputMode::TextBox)
+ return parent::loadPostData($key, $values);
+ $value = $this->getDateFromPostData($key, $values);
+ if(!$this->getReadOnly() && $this->getText()!==$value)
+ {
+ $this->setText($value);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads date from drop down list data.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return array the date selected
+ */
+ protected function getDateFromPostData($key, $values)
+ {
+ $date = @getdate();
+
+ if(isset($values[$key.'$day']))
+ $day = intval($values[$key.'$day']);
+ else
+ $day = $date['mday'];
+
+ if(isset($values[$key.'$month']))
+ $month = intval($values[$key.'$month']) + 1;
+ else
+ $month = $date['mon'];
+
+ if(isset($values[$key.'$year']))
+ $year = intval($values[$key.'$year']);
+ else
+ $year = $date['year'];
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getTimeStamp(0, 0, 0, $month, $day, $year);
+ //$date = @mktime(0, 0, 0, $month, $day, $year);
+
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter', $pattern);
+ return $formatter->format($date);
+ }
+
+ /**
+ * Get javascript date picker options.
+ * @return array date picker client-side options
+ */
+ protected function getDatePickerOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['InputMode'] = $this->getInputMode();
+ $options['Format'] = $this->getDateFormat();
+ $options['FirstDayOfWeek'] = $this->getFirstDayOfWeek();
+ if(($cssClass=$this->getCssClass())!=='')
+ $options['ClassName'] = $cssClass;
+ $options['CalendarStyle'] = $this->getCalendarStyle();
+ $options['FromYear'] = $this->getFromYear();
+ $options['UpToYear'] = $this->getUpToYear();
+ switch($this->getMode())
+ {
+ case TDatePickerMode::Basic:
+ break;
+ case TDatePickerMode::Clickable:
+ $options['TriggerEvent'] = "click";
+ break;
+ default:
+ $options['Trigger'] = $this->getDatePickerButtonID();
+ break;
+ }
+ $options['PositionMode'] = $this->getPositionMode();
+
+ $options = array_merge($options, $this->getCulturalOptions());
+ if($this->_clientScript!==null)
+ $options = array_merge($options,
+ $this->_clientScript->getOptions()->toArray());
+ return $options;
+ }
+
+ /**
+ * Get javascript localization options, e.g. month and weekday names.
+ * @return array localization options.
+ */
+ protected function getCulturalOptions()
+ {
+ if($this->getCurrentCulture() == 'en')
+ return array();
+
+ $date = $this->getLocalizedCalendarInfo();
+ $options['MonthNames'] = $date->getMonthNames();
+ $options['AbbreviatedMonthNames'] = $date->getAbbreviatedMonthNames();
+ $options['ShortWeekDayNames'] = $date->getAbbreviatedDayNames();
+
+ return $options;
+ }
+
+ /**
+ * @return string the current culture, falls back to application if culture is not set.
+ */
+ protected function getCurrentCulture()
+ {
+ $app = $this->getApplication()->getGlobalization(false);
+ return $this->getCulture() == '' ?
+ ($app ? $app->getCulture() : 'en') : $this->getCulture();
+ }
+
+ /**
+ * @return DateTimeFormatInfo date time format information for the current culture.
+ */
+ protected function getLocalizedCalendarInfo()
+ {
+ //expensive operations
+ $culture = $this->getCurrentCulture();
+ Prado::using('System.I18N.core.DateTimeFormatInfo');
+ $info = Prado::createComponent('System.I18N.core.CultureInfo', $culture);
+ return $info->getDateTimeFormat();
+ }
+
+ /**
+ * Renders the drop down list date picker.
+ */
+ protected function renderDropDownListCalendar($writer)
+ {
+ if($this->getMode() == TDatePickerMode::Basic)
+ $this->setMode(TDatePickerMode::ImageButton);
+ parent::addAttributesToRender($writer);
+ $writer->removeAttribute('name');
+ $writer->removeAttribute('type');
+ $writer->addAttribute('id', $this->getClientID());
+
+ if(strlen($class = $this->getCssClass()) > 0)
+ $writer->addAttribute('class', $class);
+ $writer->renderBeginTag('span');
+
+ $s = Prado::createComponent('System.Util.TDateTimeStamp');
+ $date = $s->getDate($this->getTimeStampFromText());
+ //$date = @getdate($this->getTimeStampFromText());
+
+ $this->renderCalendarSelections($writer, $date);
+
+ //render a hidden input field
+ $writer->addAttribute('name', $this->getUniqueID());
+ $writer->addAttribute('type', 'hidden');
+ $writer->addAttribute('value', $this->getText());
+ $writer->renderBeginTag('input');
+
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+
+ protected function hasDayPattern()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ return ($formatter->getDayPattern()!==null);
+ }
+
+ /**
+ * Renders the calendar drop down list depending on the DateFormat pattern.
+ * @param THtmlWriter the Html writer to render the drop down lists.
+ * @param array the current selected date
+ */
+ protected function renderCalendarSelections($writer, $date)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+
+ foreach($formatter->getDayMonthYearOrdering() as $type)
+ {
+ if($type == 'day')
+ $this->renderCalendarDayOptions($writer,$date['mday']);
+ elseif($type == 'month')
+ $this->renderCalendarMonthOptions($writer,$date['mon']);
+ elseif($type == 'year')
+ $this->renderCalendarYearOptions($writer,$date['year']);
+ }
+ }
+
+ /**
+ * Gets the date from the text input using TSimpleDateFormatter
+ * @return integer current selected date timestamp
+ */
+ protected function getTimeStampFromText()
+ {
+ $pattern = $this->getDateFormat();
+ $pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',$pattern);
+ return $formatter->parse($this->getText());
+ }
+
+ /**
+ * Renders a drop down lists.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param array list of selection options
+ * @param mixed selected key.
+ */
+ private function renderDropDownListOptions($writer,$options,$selected=null)
+ {
+ foreach($options as $k => $v)
+ {
+ $writer->addAttribute('value', $k);
+ if($k == $selected)
+ $writer->addAttribute('selected', 'selected');
+ $writer->renderBeginTag('option');
+ $writer->write($v);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the day drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected day.
+ */
+ protected function renderCalendarDayOptions($writer, $selected=null)
+ {
+ $days = $this->getDropDownDayOptions();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'day');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'day');
+ $writer->addAttribute('class', 'datepicker_day_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer, $days, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @return array list of day options for a drop down list.
+ */
+ protected function getDropDownDayOptions()
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ $days = array();
+ $requiresPadding = $formatter->getDayPattern() === 'dd';
+ for($i=1;$i<=31;$i++)
+ {
+ $days[$i] = $requiresPadding ? str_pad($i, 2, '0', STR_PAD_LEFT) : $i;
+ }
+ return $days;
+ }
+
+ /**
+ * Renders the month drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected month.
+ */
+ protected function renderCalendarMonthOptions($writer, $selected=null)
+ {
+ $info = $this->getLocalizedCalendarInfo();
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'month');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'month');
+ $writer->addAttribute('class', 'datepicker_month_options');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $this->renderDropDownListOptions($writer,
+ $this->getLocalizedMonthNames($info), $selected-1);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Returns the localized month names that depends on the month format pattern.
+ * "MMMM" will return the month names, "MM" or "MMM" return abbr. month names
+ * and "M" return month digits.
+ * @param DateTimeFormatInfo localized date format information.
+ * @return array localized month names.
+ */
+ protected function getLocalizedMonthNames($info)
+ {
+ $formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
+ $this->getDateFormat());
+ switch($formatter->getMonthPattern())
+ {
+ case 'MMM': return $info->getAbbreviatedMonthNames();
+ case 'MM':
+ $array = array();
+ for($i=1;$i<=12;$i++)
+ $array[$i-1] = $i < 10 ? '0'.$i : $i;
+ return $array;
+ case 'M':
+ $array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
+ return $array;
+ default : return $info->getMonthNames();
+ }
+ }
+
+ /**
+ * Renders the year drop down list options.
+ * @param THtmlWriter the writer used for the rendering purpose
+ * @param mixed selected year.
+ */
+ protected function renderCalendarYearOptions($writer, $selected=null)
+ {
+ $years = array();
+ for($i = $this->getFromYear(); $i <= $this->getUpToYear(); $i++)
+ $years[$i] = $i;
+ $writer->addAttribute('id', $this->getClientID().TControl::CLIENT_ID_SEPARATOR.'year');
+ $writer->addAttribute('name', $this->getUniqueID().TControl::ID_SEPARATOR.'year');
+ if($this->getReadOnly() || !$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag('select');
+ $writer->addAttribute('class', 'datepicker_year_options');
+ $this->renderDropDownListOptions($writer, $years, $selected);
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Gets the ID for the date picker trigger button.
+ * @return string unique button ID
+ */
+ protected function getDatePickerButtonID()
+ {
+ return $this->getClientID().'button';
+ }
+
+ /**
+ * Adds an additional button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderButtonDatePicker($writer)
+ {
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('type', 'button');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerButton');
+ $writer->addAttribute('value',$this->getButtonText());
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->renderBeginTag("input");
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Adds an additional image button such that when clicked it shows the date picker.
+ * @return THtmlWriter writer
+ */
+ protected function renderImageButtonDatePicker($writer)
+ {
+ $url = $this->getButtonImageUrl();
+ $url = empty($url) ? $this->getAssetUrl('calendar.png') : $url;
+ $writer->addAttribute('id', $this->getDatePickerButtonID());
+ $writer->addAttribute('src', $url);
+ $writer->addAttribute('alt', ' ');
+ $writer->addAttribute('class', $this->getCssClass().' TDatePickerImageButton');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled', 'disabled');
+ $writer->addAttribute('type', 'image');
+ $writer->addAttribute('onclick', 'return false;');
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * @param string date picker asset file in the self::SCRIPT_PATH directory.
+ * @return string date picker asset url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Publish the calendar style Css asset file.
+ * @return string Css file url.
+ */
+ protected function publishCalendarStyle()
+ {
+ $url = $this->getAssetUrl($this->getCalendarStyle().'.css');
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * Add the client id to the input textbox, and register the client scripts.
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ $this->registerCalendarClientScriptPost();
+ }
+
+
+ /**
+ * Registers the javascript code to initialize the date picker.
+ */
+ protected function registerCalendarClientScriptPre()
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript("datepicker");
+ }
+ }
+
+ protected function registerCalendarClientScriptPost()
+ {
+ if($this->getShowCalendar())
+ {
+ $cs = $this->getPage()->getClientScript();
+ if(!$cs->isEndScriptRegistered('TDatePicker.spacer'))
+ {
+ $spacer = $this->getAssetUrl('spacer.gif');
+ $code = "Prado.WebUI.TDatePicker.spacer = '$spacer';";
+ $cs->registerEndScript('TDatePicker.spacer', $code);
+ }
+
+ $options = TJavaScript::encode($this->getDatePickerOptions());
+ $code = "new Prado.WebUI.TDatePicker($options);";
+ $cs->registerEndScript("prado:".$this->getClientID(), $code);
+ }
+ }
+}
+
+/**
+ * TDatePickerClientScript class.
+ *
+ * Client-side date picker event {@link setOnDateChanged OnDateChanged}
+ * can be modified through the {@link TDatePicker::getClientSide ClientSide}
+ * property of a date picker.
+ *
+ * The <tt>OnDateChanged</tt> event is raise when the date picker's date
+ * is changed.
+ * The formatted date according to {@link TDatePicker::getDateFormat DateFormat} is sent
+ * as parameter to this event
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerClientScript extends TClientSideOptions
+{
+ /**
+ * Javascript code to execute when the date picker's date is changed.
+ * @param string javascript code
+ */
+ public function setOnDateChanged($javascript)
+ {
+ $this->setFunction('OnDateChanged', $javascript);
+ }
+
+ /**
+ * @return string javascript code to execute when the date picker's date is changed.
+ */
+ public function getOnDateChanged()
+ {
+ return $this->getOption('OnDateChanged');
+ }
+}
+
+
+/**
+ * TDatePickerInputMode class.
+ * TDatePickerInputMode defines the enumerable type for the possible datepicker input methods.
+ *
+ * The following enumerable values are defined:
+ * - TextBox: text boxes are used to input date values
+ * - DropDownList: dropdown lists are used to pick up date values
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerInputMode extends TEnumerable
+{
+ const TextBox='TextBox';
+ const DropDownList='DropDownList';
+}
+
+/**
+ * TDatePickerMode class.
+ * TDatePickerMode defines the enumerable type for the possible UI mode
+ * that a {@link TDatePicker} control can take.
+ *
+ * The following enumerable values are defined:
+ * - Basic: Only shows a text input, focusing on the input shows the date picker
+ * - Clickable: Only shows a text input, clicking on the input shows the date picker (since 3.2)
+ * - Button: Shows a button next to the text input, clicking on the button shows the date, button text can be by the
+ * - ImageButton: Shows an image next to the text input, clicking on the image shows the date picker,
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDatePickerMode extends TEnumerable
+{
+ const Basic='Basic';
+ const Clickable='Clickable';
+ const Button='Button';
+ const ImageButton='ImageButton';
+}
+
+/**
+ * TDatePickerPositionMode class.
+ * TDatePickerPositionMode defines the positions available for the calendar popup, relative to the corresponding input.
+ *
+ * The following enumerable values are defined:
+ * - Top: the date picker is placed above the input field
+ * - Bottom: the date picker is placed below the input field
+ *
+ * @author Carl G. Mathisen <carlgmathisen@gmail.com>
+ * @package System.Web.UI.WebControls
+ * @since 3.1.4
+ */
+class TDatePickerPositionMode extends TEnumerable
+{
+ const Top='Top';
+ const Bottom='Bottom';
+}
diff --git a/framework/Web/UI/WebControls/TDropDownList.php b/framework/Web/UI/WebControls/TDropDownList.php
index 0eba6285..57f1f165 100644
--- a/framework/Web/UI/WebControls/TDropDownList.php
+++ b/framework/Web/UI/WebControls/TDropDownList.php
@@ -1,154 +1,154 @@
-<?php
-/**
- * TDropDownList class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TDropDownList class
- *
- * TDropDownList displays a dropdown list on a Web page.
- * It inherits all properties and events from {@link TListControl}.
- *
- * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
- * a list item, set a Group attribute with it,
- * <code>
- * $listitem->Attributes->Group="Group Name";
- * // or <com:TListItem Attributes.Group="Group Name" .../> in template
- * </code>
- *
- * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
- * displayed as the first list item by specifying either {@link setPromptText PromptText} or
- * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
- *
- * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
- * property is not affected by a prompt item: the items list will still be zero-based.
- *
- * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
- * available item in the dropdown list will be selected.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
-{
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('name',$this->getUniqueID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TDropDownList';
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if(!$this->getEnabled(true))
- return false;
- $this->ensureDataBound();
- $selection=isset($values[$key])?$values[$key]:null;
- if($selection!==null)
- {
- $index=$this->getItems()->findIndexByValue($selection,false);
- if($this->getSelectedIndex()!==$index)
- {
- $this->setSelectedIndex($index);
- return $this->_dataChanged=true;
- }
- }
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @throws TNotSupportedException if this method is invoked
- */
- public function setSelectedIndices($indices)
- {
- throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-}
+<?php
+/**
+ * TDropDownList class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TDropDownList class
+ *
+ * TDropDownList displays a dropdown list on a Web page.
+ * It inherits all properties and events from {@link TListControl}.
+ *
+ * Since v3.0.3, TDropDownList starts to support optgroup. To specify an option group for
+ * a list item, set a Group attribute with it,
+ * <code>
+ * $listitem->Attributes->Group="Group Name";
+ * // or <com:TListItem Attributes.Group="Group Name" .../> in template
+ * </code>
+ *
+ * Since v3.1.1, TDropDownList starts to support prompt text. That is, a prompt item can be
+ * displayed as the first list item by specifying either {@link setPromptText PromptText} or
+ * {@link setPromptValue PromptValue}, or both. Choosing the prompt item will unselect the TDropDownList.
+ *
+ * When a prompt item is set, its index in the list is set to -1. So, the {@link getSelectedIndex SelectedIndex}
+ * property is not affected by a prompt item: the items list will still be zero-based.
+ *
+ * The {@link clearSelection clearSelection} method will select the prompt item if existing, otherway the first
+ * available item in the dropdown list will be selected.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TDropDownList extends TListControl implements IPostBackDataHandler, IValidatable
+{
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('name',$this->getUniqueID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TDropDownList';
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(!$this->getEnabled(true))
+ return false;
+ $this->ensureDataBound();
+ $selection=isset($values[$key])?$values[$key]:null;
+ if($selection!==null)
+ {
+ $index=$this->getItems()->findIndexByValue($selection,false);
+ if($this->getSelectedIndex()!==$index)
+ {
+ $this->setSelectedIndex($index);
+ return $this->_dataChanged=true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndex SelectedIndex} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @throws TNotSupportedException if this method is invoked
+ */
+ public function setSelectedIndices($indices)
+ {
+ throw new TNotSupportedException('dropdownlist_selectedindices_unsupported');
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+}
diff --git a/framework/Web/UI/WebControls/TDropDownListColumn.php b/framework/Web/UI/WebControls/TDropDownListColumn.php
index ffbe8f70..941a9be1 100644
--- a/framework/Web/UI/WebControls/TDropDownListColumn.php
+++ b/framework/Web/UI/WebControls/TDropDownListColumn.php
@@ -1,321 +1,321 @@
-<?php
-/**
- * TDropDownListColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TDropDownListColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-Prado::using('System.Web.UI.WebControls.TDropDownList');
-
-/**
- * TDropDownListColumn class
- *
- * TDropDownListColumn represents a column that is bound to a field in a data source.
- * The cells in the column will be displayed using the data indexed by
- * {@link setDataTextField DataTextField}. You can customize the display by
- * setting {@link setDataTextFormatString DataTextFormatString}.
- *
- * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
- * with dropdown lists. Otherwise, a static text is displayed.
- * The currently selected dropndown list item is specified by the data indexed with
- * {@link setDataValueField DataValueField}.
- *
- * There are two approaches to specify the list items available for selection.
- * The first approach uses template syntax as follows,
- * <code>
- * <com:TDropDownListColumn ....>
- * <com:TListItem Value="1" Text="first item" />
- * <com:TListItem Value="2" Text="second item" />
- * <com:TListItem Value="3" Text="third item" />
- * </com:TDropDownListColumn>
- * </code>
- * The second approach specifies a data source to be bound to the dropdown lists
- * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
- * you may also want to specify which data fields are used for item values and texts
- * by setting {@link setListValueField ListValueField} and
- * {@link setListTextField ListTextField}, respectively.
- * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
- * Note, if you specify {@link setListDataSource ListDataSource}, do it before
- * calling the datagrid's dataBind().
- *
- * The dropdown list control in the TDropDownListColumn can be accessed by one of
- * the following two methods:
- * <code>
- * $datagridItem->DropDownListColumnID->DropDownList
- * $datagridItem->DropDownListColumnID->Controls[0]
- * </code>
- * The second method is possible because the dropdown list control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TDropDownListColumn extends TDataGridColumn
-{
- private $_stateLoaded=false;
- private $_dataBound=false;
- private $_listControl=null;
-
- public function __construct()
- {
- $this->_listControl=new TDropDownList;
- }
-
- /**
- * Loads items from viewstate.
- * This method overrides the parent implementation by loading list items
- * @param mixed state values
- */
- public function loadState($state)
- {
- parent::loadState($state);
- $this->_stateLoaded=true;
- if(!$this->_dataBound)
- $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
- }
-
- /**
- * Saves items into viewstate.
- * This method overrides the parent implementation by saving list items
- */
- public function saveState()
- {
- $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
- return parent::saveState();
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- // Do not add items from template if items are loaded from viewstate
- if(!$this->_stateLoaded && ($object instanceof TListItem))
- {
- $object->setSelected(false);
- $index=$this->_listControl->getItems()->add($object);
- }
- }
-
- /**
- * @return string the field of the data source that provides the text content of the column.
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * Sets the field of the data source that provides the text content of the column.
- * If this is not set, the data specified via {@link getDataValueField DataValueField}
- * will be displayed in the column.
- * @param string the field of the data source that provides the text content of the column.
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function getDataValueField()
- {
- return $this->getViewState('DataValueField','');
- }
-
- /**
- * Sets the field of the data source that provides the key selecting an item in dropdown list.
- * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
- * applying the formatting string) will be used for selection, instead.
- * @param string the field of the data source that provides the key selecting an item in dropdown list.
- */
- public function setDataValueField($value)
- {
- $this->setViewState('DataValueField',$value,'');
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return Traversable data source to be bound to the dropdown list boxes.
- */
- public function getListDataSource()
- {
- return $this->_listControl->getDataSource();
- }
-
- /**
- * @param Traversable|array|string data source to be bound to the dropdown list boxes.
- */
- public function setListDataSource($value)
- {
- $this->_listControl->setDataSource($value);
- }
-
- /**
- * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
- */
- public function getListValueField()
- {
- return $this->getViewState('ListValueField','');
- }
-
- /**
- * @param string the data field used to populate the values of the dropdown list items
- */
- public function setListValueField($value)
- {
- $this->setViewState('ListValueField',$value,'');
- }
-
- /**
- * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
- */
- public function getListTextField()
- {
- return $this->getViewState('ListTextField','');
- }
-
- /**
- * @param string the data field used to populate the texts of the dropdown list items
- */
- public function setListTextField($value)
- {
- $this->setViewState('ListTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the list item texts will be displayed.
- */
- public function getListTextFormatString()
- {
- return $this->getViewState('ListTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the list item texts will be displayed.
- */
- public function setListTextFormatString($value)
- {
- $this->setViewState('ListTextFormatString',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a textbox for item in edit mode and the column is not read-only.
- * Otherwise it displays a static text.
- * The caption of the button and the static text are retrieved
- * from the datasource.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
- {
- $this->_listControl->setDataTextField($this->getListTextField());
- $this->_listControl->setDataValueField($this->getListValueField());
- $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
- $this->_listControl->dataBind();
- $this->_dataBound=true;
- }
- switch($itemType)
- {
- case TListItemType::EditItem:
- if(!$this->getReadOnly())
- {
- $listControl=clone $this->_listControl;
- $cell->getControls()->add($listControl);
- $cell->registerObject('DropDownList',$listControl);
- $control=$listControl;
- }
- else
- $control=$cell;
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- case TListItemType::Item:
- case TListItemType::AlternatingItem:
- case TListItemType::SelectedItem:
- if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
- $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- break;
- default:
- parent::initializeCell($cell,$columnIndex,$itemType);
- break;
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($valueField=$this->getDataValueField())!=='')
- $value=$this->getDataFieldValue($data,$valueField);
- else
- $value='';
- if(($textField=$this->getDataTextField())!=='')
- {
- $text=$this->getDataFieldValue($data,$textField);
- if($valueField==='')
- $value=$text;
- $formatString=$this->getDataTextFormatString();
- $text=$this->formatDataValue($formatString,$text);
- }
- else
- $text=$value;
- if($sender instanceof TTableCell)
- $sender->setText($text);
- else if($sender instanceof TDropDownList)
- $sender->setSelectedValue($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+Prado::using('System.Web.UI.WebControls.TDropDownList');
+
+/**
+ * TDropDownListColumn class
+ *
+ * TDropDownListColumn represents a column that is bound to a field in a data source.
+ * The cells in the column will be displayed using the data indexed by
+ * {@link setDataTextField DataTextField}. You can customize the display by
+ * setting {@link setDataTextFormatString DataTextFormatString}.
+ *
+ * If {@link setReadOnly ReadOnly} is false, TDropDownListColumn will display cells in edit mode
+ * with dropdown lists. Otherwise, a static text is displayed.
+ * The currently selected dropndown list item is specified by the data indexed with
+ * {@link setDataValueField DataValueField}.
+ *
+ * There are two approaches to specify the list items available for selection.
+ * The first approach uses template syntax as follows,
+ * <code>
+ * <com:TDropDownListColumn ....>
+ * <com:TListItem Value="1" Text="first item" />
+ * <com:TListItem Value="2" Text="second item" />
+ * <com:TListItem Value="3" Text="third item" />
+ * </com:TDropDownListColumn>
+ * </code>
+ * The second approach specifies a data source to be bound to the dropdown lists
+ * by setting {@link setListDataSource ListDataSource}. Like generic list controls,
+ * you may also want to specify which data fields are used for item values and texts
+ * by setting {@link setListValueField ListValueField} and
+ * {@link setListTextField ListTextField}, respectively.
+ * Furthermore, the item texts may be formatted by using {@link setListTextFormatString ListTextFormatString}.
+ * Note, if you specify {@link setListDataSource ListDataSource}, do it before
+ * calling the datagrid's dataBind().
+ *
+ * The dropdown list control in the TDropDownListColumn can be accessed by one of
+ * the following two methods:
+ * <code>
+ * $datagridItem->DropDownListColumnID->DropDownList
+ * $datagridItem->DropDownListColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the dropdown list control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TDropDownListColumn extends TDataGridColumn
+{
+ private $_stateLoaded=false;
+ private $_dataBound=false;
+ private $_listControl=null;
+
+ public function __construct()
+ {
+ $this->_listControl=new TDropDownList;
+ }
+
+ /**
+ * Loads items from viewstate.
+ * This method overrides the parent implementation by loading list items
+ * @param mixed state values
+ */
+ public function loadState($state)
+ {
+ parent::loadState($state);
+ $this->_stateLoaded=true;
+ if(!$this->_dataBound)
+ $this->_listControl->getItems()->loadState($this->getViewState('Items',null));
+ }
+
+ /**
+ * Saves items into viewstate.
+ * This method overrides the parent implementation by saving list items
+ */
+ public function saveState()
+ {
+ $this->setViewState('Items',$this->_listControl->getItems()->saveState(),null);
+ return parent::saveState();
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ // Do not add items from template if items are loaded from viewstate
+ if(!$this->_stateLoaded && ($object instanceof TListItem))
+ {
+ $object->setSelected(false);
+ $index=$this->_listControl->getItems()->add($object);
+ }
+ }
+
+ /**
+ * @return string the field of the data source that provides the text content of the column.
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the text content of the column.
+ * If this is not set, the data specified via {@link getDataValueField DataValueField}
+ * will be displayed in the column.
+ * @param string the field of the data source that provides the text content of the column.
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function getDataValueField()
+ {
+ return $this->getViewState('DataValueField','');
+ }
+
+ /**
+ * Sets the field of the data source that provides the key selecting an item in dropdown list.
+ * If this is not present, the data specified via {@link getDataTextField DataTextField} (without
+ * applying the formatting string) will be used for selection, instead.
+ * @param string the field of the data source that provides the key selecting an item in dropdown list.
+ */
+ public function setDataValueField($value)
+ {
+ $this->setViewState('DataValueField',$value,'');
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return Traversable data source to be bound to the dropdown list boxes.
+ */
+ public function getListDataSource()
+ {
+ return $this->_listControl->getDataSource();
+ }
+
+ /**
+ * @param Traversable|array|string data source to be bound to the dropdown list boxes.
+ */
+ public function setListDataSource($value)
+ {
+ $this->_listControl->setDataSource($value);
+ }
+
+ /**
+ * @return string the data field used to populate the values of the dropdown list items. Defaults to empty.
+ */
+ public function getListValueField()
+ {
+ return $this->getViewState('ListValueField','');
+ }
+
+ /**
+ * @param string the data field used to populate the values of the dropdown list items
+ */
+ public function setListValueField($value)
+ {
+ $this->setViewState('ListValueField',$value,'');
+ }
+
+ /**
+ * @return string the data field used to populate the texts of the dropdown list items. Defaults to empty.
+ */
+ public function getListTextField()
+ {
+ return $this->getViewState('ListTextField','');
+ }
+
+ /**
+ * @param string the data field used to populate the texts of the dropdown list items
+ */
+ public function setListTextField($value)
+ {
+ $this->setViewState('ListTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function getListTextFormatString()
+ {
+ return $this->getViewState('ListTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the list item texts will be displayed.
+ */
+ public function setListTextFormatString($value)
+ {
+ $this->setViewState('ListTextFormatString',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a textbox for item in edit mode and the column is not read-only.
+ * Otherwise it displays a static text.
+ * The caption of the button and the static text are retrieved
+ * from the datasource.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if(!$this->_dataBound && $this->_listControl->getDataSource()!==null)
+ {
+ $this->_listControl->setDataTextField($this->getListTextField());
+ $this->_listControl->setDataValueField($this->getListValueField());
+ $this->_listControl->setDataTextFormatString($this->getListTextFormatString());
+ $this->_listControl->dataBind();
+ $this->_dataBound=true;
+ }
+ switch($itemType)
+ {
+ case TListItemType::EditItem:
+ if(!$this->getReadOnly())
+ {
+ $listControl=clone $this->_listControl;
+ $cell->getControls()->add($listControl);
+ $cell->registerObject('DropDownList',$listControl);
+ $control=$listControl;
+ }
+ else
+ $control=$cell;
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ case TListItemType::Item:
+ case TListItemType::AlternatingItem:
+ case TListItemType::SelectedItem:
+ if($this->getDataTextField()!=='' || $this->getDataValueField()!=='')
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ break;
+ default:
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ break;
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($valueField=$this->getDataValueField())!=='')
+ $value=$this->getDataFieldValue($data,$valueField);
+ else
+ $value='';
+ if(($textField=$this->getDataTextField())!=='')
+ {
+ $text=$this->getDataFieldValue($data,$textField);
+ if($valueField==='')
+ $value=$text;
+ $formatString=$this->getDataTextFormatString();
+ $text=$this->formatDataValue($formatString,$text);
+ }
+ else
+ $text=$value;
+ if($sender instanceof TTableCell)
+ $sender->setText($text);
+ else if($sender instanceof TDropDownList)
+ $sender->setSelectedValue($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TEditCommandColumn.php b/framework/Web/UI/WebControls/TEditCommandColumn.php
index 44004807..b10c6880 100644
--- a/framework/Web/UI/WebControls/TEditCommandColumn.php
+++ b/framework/Web/UI/WebControls/TEditCommandColumn.php
@@ -1,265 +1,265 @@
-<?php
-/**
- * TEditCommandColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TEditCommandColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TEditCommandColumn class
- *
- * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
- *
- * TEditCommandColumn will create an edit button if a cell is not in edit mode.
- * Otherwise an update button and a cancel button will be created within the cell.
- * The button captions are specified using {@link setEditText EditText},
- * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
- *
- * The buttons in the column can be set to display as hyperlinks, push or image buttons
- * by setting the {@link setButtonType ButtonType} property.
- *
- * When an edit button is clicked, the datagrid will generate an
- * {@link onEditCommand OnEditCommand} event. When an update/cancel button
- * is clicked, the datagrid will generate an
- * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
- * You can write these event handlers to change the state of specific datagrid item.
- *
- * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
- * properties affect the corresponding properties of the edit and update buttons.
- * The cancel button does not cause validation by default.
- *
- * The command buttons in the column can be accessed by one of the following methods:
- * <code>
- * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
- * $datagridItem->ButtonColumnID->Controls[0]
- * </code>
- * The second method is possible because the button control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEditCommandColumn extends TDataGridColumn
-{
- /**
- * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
- }
-
- /**
- * @param TButtonColumnType the type of command button.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
- }
-
- /**
- * @return string the caption of the edit button. Defaults to 'Edit'.
- */
- public function getEditText()
- {
- return $this->getViewState('EditText','Edit');
- }
-
- /**
- * @param string the caption of the edit button
- */
- public function setEditText($value)
- {
- $this->setViewState('EditText',$value,'Edit');
- }
-
- /**
- * @return string the URL of the image file for edit image buttons
- */
- public function getEditImageUrl()
- {
- return $this->getViewState('EditImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for edit image buttons
- */
- public function setEditImageUrl($value)
- {
- $this->setViewState('EditImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the update button. Defaults to 'Update'.
- */
- public function getUpdateText()
- {
- return $this->getViewState('UpdateText','Update');
- }
-
- /**
- * @param string the caption of the update button
- */
- public function setUpdateText($value)
- {
- $this->setViewState('UpdateText',$value,'Update');
- }
-
- /**
- * @return string the URL of the image file for update image buttons
- */
- public function getUpdateImageUrl()
- {
- return $this->getViewState('UpdateImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for update image buttons
- */
- public function setUpdateImageUrl($value)
- {
- $this->setViewState('UpdateImageUrl',$value,'');
- }
-
- /**
- * @return string the caption of the cancel button. Defaults to 'Cancel'.
- */
- public function getCancelText()
- {
- return $this->getViewState('CancelText','Cancel');
- }
-
- /**
- * @param string the caption of the cancel button
- */
- public function setCancelText($value)
- {
- $this->setViewState('CancelText',$value,'Cancel');
- }
-
- /**
- * @return string the URL of the image file for cancel image buttons
- */
- public function getCancelImageUrl()
- {
- return $this->getViewState('CancelImageUrl','');
- }
-
- /**
- * @param string the URL of the image file for cancel image buttons
- */
- public function setCancelImageUrl($value)
- {
- $this->setViewState('CancelImageUrl',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by edit or update button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the edit or update button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the edit or update button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates an update and a cancel button for cell in edit mode.
- * Otherwise it creates an edit button.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
- {
- $button=$this->createButton('Edit',$this->getEditText(),false,'');
- $cell->getControls()->add($button);
- $cell->registerObject('EditButton',$button);
- }
- else if($itemType===TListItemType::EditItem)
- {
- $controls=$cell->getControls();
- $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
- $controls->add($button);
- $cell->registerObject('UpdateButton',$button);
- $controls->add('&nbsp;');
- $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
- $controls->add($button);
- $cell->registerObject('CancelButton',$button);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Creates a button and initializes its properties.
- * The button type is determined by {@link getButtonType ButtonType}.
- * @param string command name associated with the button
- * @param string button caption
- * @param boolean whether the button should cause validation
- * @param string the validation group that the button belongs to
- * @return mixed the newly created button.
- */
- protected function createButton($commandName,$text,$causesValidation,$validationGroup)
- {
- if($this->getButtonType()===TButtonColumnType::LinkButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
- else if($this->getButtonType()===TButtonColumnType::PushButton)
- $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
- else // image buttons
- {
- $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
- if(strcasecmp($commandName,'Update')===0)
- $url=$this->getUpdateImageUrl();
- else if(strcasecmp($commandName,'Cancel')===0)
- $url=$this->getCancelImageUrl();
- else
- $url=$this->getEditImageUrl();
- $button->setImageUrl($url);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCausesValidation($causesValidation);
- $button->setValidationGroup($validationGroup);
- return $button;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TEditCommandColumn class
+ *
+ * TEditCommandColumn contains the Edit command buttons for editing data items in each row.
+ *
+ * TEditCommandColumn will create an edit button if a cell is not in edit mode.
+ * Otherwise an update button and a cancel button will be created within the cell.
+ * The button captions are specified using {@link setEditText EditText},
+ * {@link setUpdateText UpdateText}, and {@link setCancelText CancelText}.
+ *
+ * The buttons in the column can be set to display as hyperlinks, push or image buttons
+ * by setting the {@link setButtonType ButtonType} property.
+ *
+ * When an edit button is clicked, the datagrid will generate an
+ * {@link onEditCommand OnEditCommand} event. When an update/cancel button
+ * is clicked, the datagrid will generate an
+ * {@link onUpdateCommand OnUpdateCommand} or an {@link onCancelCommand OnCancelCommand}
+ * You can write these event handlers to change the state of specific datagrid item.
+ *
+ * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
+ * properties affect the corresponding properties of the edit and update buttons.
+ * The cancel button does not cause validation by default.
+ *
+ * The command buttons in the column can be accessed by one of the following methods:
+ * <code>
+ * $datagridItem->ButtonColumnID->EditButton (or UpdateButton, CancelButton)
+ * $datagridItem->ButtonColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the button control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEditCommandColumn extends TDataGridColumn
+{
+ /**
+ * @return TButtonColumnType the type of command button. Defaults to TButtonColumnType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @param TButtonColumnType the type of command button.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TButtonColumnType'),TButtonColumnType::LinkButton);
+ }
+
+ /**
+ * @return string the caption of the edit button. Defaults to 'Edit'.
+ */
+ public function getEditText()
+ {
+ return $this->getViewState('EditText','Edit');
+ }
+
+ /**
+ * @param string the caption of the edit button
+ */
+ public function setEditText($value)
+ {
+ $this->setViewState('EditText',$value,'Edit');
+ }
+
+ /**
+ * @return string the URL of the image file for edit image buttons
+ */
+ public function getEditImageUrl()
+ {
+ return $this->getViewState('EditImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for edit image buttons
+ */
+ public function setEditImageUrl($value)
+ {
+ $this->setViewState('EditImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the update button. Defaults to 'Update'.
+ */
+ public function getUpdateText()
+ {
+ return $this->getViewState('UpdateText','Update');
+ }
+
+ /**
+ * @param string the caption of the update button
+ */
+ public function setUpdateText($value)
+ {
+ $this->setViewState('UpdateText',$value,'Update');
+ }
+
+ /**
+ * @return string the URL of the image file for update image buttons
+ */
+ public function getUpdateImageUrl()
+ {
+ return $this->getViewState('UpdateImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for update image buttons
+ */
+ public function setUpdateImageUrl($value)
+ {
+ $this->setViewState('UpdateImageUrl',$value,'');
+ }
+
+ /**
+ * @return string the caption of the cancel button. Defaults to 'Cancel'.
+ */
+ public function getCancelText()
+ {
+ return $this->getViewState('CancelText','Cancel');
+ }
+
+ /**
+ * @param string the caption of the cancel button
+ */
+ public function setCancelText($value)
+ {
+ $this->setViewState('CancelText',$value,'Cancel');
+ }
+
+ /**
+ * @return string the URL of the image file for cancel image buttons
+ */
+ public function getCancelImageUrl()
+ {
+ return $this->getViewState('CancelImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file for cancel image buttons
+ */
+ public function setCancelImageUrl($value)
+ {
+ $this->setViewState('CancelImageUrl',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by edit or update button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by edit or update button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the edit or update button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates an update and a cancel button for cell in edit mode.
+ * Otherwise it creates an edit button.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
+ {
+ $button=$this->createButton('Edit',$this->getEditText(),false,'');
+ $cell->getControls()->add($button);
+ $cell->registerObject('EditButton',$button);
+ }
+ else if($itemType===TListItemType::EditItem)
+ {
+ $controls=$cell->getControls();
+ $button=$this->createButton('Update',$this->getUpdateText(),$this->getCausesValidation(),$this->getValidationGroup());
+ $controls->add($button);
+ $cell->registerObject('UpdateButton',$button);
+ $controls->add('&nbsp;');
+ $button=$this->createButton('Cancel',$this->getCancelText(),false,'');
+ $controls->add($button);
+ $cell->registerObject('CancelButton',$button);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Creates a button and initializes its properties.
+ * The button type is determined by {@link getButtonType ButtonType}.
+ * @param string command name associated with the button
+ * @param string button caption
+ * @param boolean whether the button should cause validation
+ * @param string the validation group that the button belongs to
+ * @return mixed the newly created button.
+ */
+ protected function createButton($commandName,$text,$causesValidation,$validationGroup)
+ {
+ if($this->getButtonType()===TButtonColumnType::LinkButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
+ else if($this->getButtonType()===TButtonColumnType::PushButton)
+ $button=Prado::createComponent('System.Web.UI.WebControls.TButton');
+ else // image buttons
+ {
+ $button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
+ if(strcasecmp($commandName,'Update')===0)
+ $url=$this->getUpdateImageUrl();
+ else if(strcasecmp($commandName,'Cancel')===0)
+ $url=$this->getCancelImageUrl();
+ else
+ $url=$this->getEditImageUrl();
+ $button->setImageUrl($url);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCausesValidation($causesValidation);
+ $button->setValidationGroup($validationGroup);
+ return $button;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TEmailAddressValidator.php b/framework/Web/UI/WebControls/TEmailAddressValidator.php
index a198ffc4..b0b51208 100644
--- a/framework/Web/UI/WebControls/TEmailAddressValidator.php
+++ b/framework/Web/UI/WebControls/TEmailAddressValidator.php
@@ -1,97 +1,97 @@
-<?php
-/**
- * TEmailAddressValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TEmailAddressValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TRegularExpressionValidator class
- */
-Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
-
-/**
- * TEmailAddressValidator class
- *
- * TEmailAddressValidator validates whether the value of an associated
- * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
- * is true, it will check MX record for the email adress, provided
- * checkdnsrr() is available in the installed PHP.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TEmailAddressValidator extends TRegularExpressionValidator
-{
- /**
- * Regular expression used to validate the email address
- */
- const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
-
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TEmailAddressValidator';
- }
-
- /**
- * @return string the regular expression that determines the pattern used to validate a field.
- */
- public function getRegularExpression()
- {
- $regex=parent::getRegularExpression();
- return $regex===''?self::EMAIL_REGEXP:$regex;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- public function evaluateIsValid()
- {
- $valid=parent::evaluateIsValid();
- if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))!=='')
- {
- if(($pos=strpos($value,'@'))!==false)
- {
- $domain=substr($value,$pos+1);
- return $domain===''?false:checkdnsrr($domain,'MX');
- }
- else
- return false;
- }
- }
- return $valid;
- }
-
- /**
- * @return boolean whether to check MX record for the email address being validated. Defaults to true.
- */
- public function getCheckMXRecord()
- {
- return $this->getViewState('CheckMXRecord',true);
- }
-
- /**
- * @param boolean whether to check MX record for the email address being validated.
- * Note, if {@link checkdnsrr} is not available, this check will not be performed.
- */
- public function setCheckMXRecord($value)
- {
- $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TRegularExpressionValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TRegularExpressionValidator');
+
+/**
+ * TEmailAddressValidator class
+ *
+ * TEmailAddressValidator validates whether the value of an associated
+ * input component is a valid email address. If {@link getCheckMXRecord CheckMXRecord}
+ * is true, it will check MX record for the email adress, provided
+ * checkdnsrr() is available in the installed PHP.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TEmailAddressValidator extends TRegularExpressionValidator
+{
+ /**
+ * Regular expression used to validate the email address
+ */
+ const EMAIL_REGEXP="\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TEmailAddressValidator';
+ }
+
+ /**
+ * @return string the regular expression that determines the pattern used to validate a field.
+ */
+ public function getRegularExpression()
+ {
+ $regex=parent::getRegularExpression();
+ return $regex===''?self::EMAIL_REGEXP:$regex;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ public function evaluateIsValid()
+ {
+ $valid=parent::evaluateIsValid();
+ if($valid && $this->getCheckMXRecord() && function_exists('checkdnsrr'))
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))!=='')
+ {
+ if(($pos=strpos($value,'@'))!==false)
+ {
+ $domain=substr($value,$pos+1);
+ return $domain===''?false:checkdnsrr($domain,'MX');
+ }
+ else
+ return false;
+ }
+ }
+ return $valid;
+ }
+
+ /**
+ * @return boolean whether to check MX record for the email address being validated. Defaults to true.
+ */
+ public function getCheckMXRecord()
+ {
+ return $this->getViewState('CheckMXRecord',true);
+ }
+
+ /**
+ * @param boolean whether to check MX record for the email address being validated.
+ * Note, if {@link checkdnsrr} is not available, this check will not be performed.
+ */
+ public function setCheckMXRecord($value)
+ {
+ $this->setViewState('CheckMXRecord',TPropertyValue::ensureBoolean($value),true);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TExpression.php b/framework/Web/UI/WebControls/TExpression.php
index 9b8eb7e7..cf38df70 100644
--- a/framework/Web/UI/WebControls/TExpression.php
+++ b/framework/Web/UI/WebControls/TExpression.php
@@ -1,62 +1,62 @@
-<?php
-/**
- * TExpression class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TExpression class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TExpression class
- *
- * TExpression evaluates a PHP expression and renders the result.
- * The expression is evaluated during the rendering stage. The expression being
- * evaluated can be set via the property {@link setExpression Expression}.
- * The context of the expression evaluated is the TExpression object itself.
- *
- * Note, since TExpression allows evaluation of arbitrary PHP expression,
- * make sure {@link setExpression Expression} does not come directly from user input.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TExpression extends TControl
-{
- /**
- * @var string PHP expression to be evaluated
- */
- private $_e='';
-
- /**
- * @return string the expression to be evaluated
- */
- public function getExpression()
- {
- return $this->_e;
- }
-
- /**
- * @param string the expression to be evaluated
- */
- public function setExpression($value)
- {
- $this->_e=$value;
- }
-
- /**
- * Renders the evaluation result of the expression.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_e!=='')
- $writer->write($this->evaluateExpression($this->_e));
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TExpression class
+ *
+ * TExpression evaluates a PHP expression and renders the result.
+ * The expression is evaluated during the rendering stage. The expression being
+ * evaluated can be set via the property {@link setExpression Expression}.
+ * The context of the expression evaluated is the TExpression object itself.
+ *
+ * Note, since TExpression allows evaluation of arbitrary PHP expression,
+ * make sure {@link setExpression Expression} does not come directly from user input.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TExpression extends TControl
+{
+ /**
+ * @var string PHP expression to be evaluated
+ */
+ private $_e='';
+
+ /**
+ * @return string the expression to be evaluated
+ */
+ public function getExpression()
+ {
+ return $this->_e;
+ }
+
+ /**
+ * @param string the expression to be evaluated
+ */
+ public function setExpression($value)
+ {
+ $this->_e=$value;
+ }
+
+ /**
+ * Renders the evaluation result of the expression.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_e!=='')
+ $writer->write($this->evaluateExpression($this->_e));
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TFileUpload.php b/framework/Web/UI/WebControls/TFileUpload.php
index 0f7d226d..051e3e0b 100644
--- a/framework/Web/UI/WebControls/TFileUpload.php
+++ b/framework/Web/UI/WebControls/TFileUpload.php
@@ -1,281 +1,281 @@
-<?php
-/**
- * TFileUpload class file
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFileUpload class
- *
- * TFileUpload displays a file upload field on a page. Upon postback,
- * the text entered into the field will be treated as the name of the file
- * that will be uploaded to the server. The property {@link getHasFile HasFile}
- * indicates whether the file upload is successful. If successful, the file
- * may be obtained by calling {@link saveAs} to save it at a specified place.
- * You can use {@link getFileName FileName}, {@link getFileType FileType},
- * {@link getFileSize FileSize} to get the original client-side file name,
- * the file mime type, and the file size information. If the upload is not
- * successful, {@link getErrorCode ErrorCode} contains the error code
- * describing the cause of failure.
- *
- * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
- * (whether it succeeds or not).
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
-{
- /**
- * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
- */
- const MAX_FILE_SIZE=1048576;
- /**
- * @var integer the size of the uploaded file (in bytes)
- */
- private $_fileSize=0;
- /**
- * @var string The original name of the file on the client machine
- */
- private $_fileName='';
- /**
- * @var string the name of the temporary file storing the uploaded file
- */
- private $_localName='';
- /**
- * @var string the uploaded file mime type
- */
- private $_fileType='';
- /**
- * @var integer error code of the current file upload
- */
- protected $_errorCode=UPLOAD_ERR_NO_FILE;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * @return string tag name of the file upload control
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets name attribute to the unique ID of the control.
- * This method overrides the parent implementation with additional file update control specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $this->getPage()->ensureRenderInForm($this);
- parent::addAttributesToRender($writer);
- $writer->addAttribute('type','file');
- $writer->addAttribute('name',$this->getUniqueID());
- $isEnabled=$this->getEnabled(true);
- if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Sets Enctype of the form on the page.
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if(($form=$this->getPage()->getForm())!==null)
- $form->setEnctype('multipart/form-data');
- $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
- * @see setMaxFileSize
- */
- public function getMaxFileSize()
- {
- return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
- }
-
- /**
- * Sets the maximum size that a file can be uploaded.
- * Note, this is an advisory value to the browser. Sets this property with
- * a reasonably large size to save users the trouble of waiting
- * for a big file being transferred only to find that it was too big
- * and the transfer failed.
- * @param int the maximum upload size allowed for a file.
- */
- public function setMaxFileSize($size)
- {
- $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
- }
-
- /**
- * @return string the original full path name of the file on the client machine
- */
- public function getFileName()
- {
- return $this->_fileName;
- }
-
- /**
- * @return integer the actual size of the uploaded file in bytes
- */
- public function getFileSize()
- {
- return $this->_fileSize;
- }
-
- /**
- * @return string the MIME-type of the uploaded file (such as "image/gif").
- * This mime type is not checked on the server side and do not take its value for granted.
- */
- public function getFileType()
- {
- return $this->_fileType;
- }
-
- /**
- * @return string the local name of the file (where it is after being uploaded).
- * Note, PHP will delete this file automatically after finishing this round of request.
- */
- public function getLocalName()
- {
- return $this->_localName;
- }
-
- /**
- * Returns an error code describing the status of this file uploading.
- * @return integer the error code
- * @see http://www.php.net/manual/en/features.file-upload.errors.php
- */
- public function getErrorCode()
- {
- return $this->_errorCode;
- }
-
- /**
- * @return boolean whether the file is uploaded successfully
- */
- public function getHasFile()
- {
- return $this->_errorCode===UPLOAD_ERR_OK;
- }
-
- /**
- * Saves the uploaded file.
- * @param string the file name used to save the uploaded file
- * @param boolean whether to delete the temporary file after saving.
- * If true, you will not be able to save the uploaded file again.
- * @return boolean true if the file saving is successful
- */
- public function saveAs($fileName,$deleteTempFile=true)
- {
- if($this->_errorCode===UPLOAD_ERR_OK)
- {
- if($deleteTempFile)
- return move_uploaded_file($this->_localName,$fileName);
- else if(is_uploaded_file($this->_localName))
- return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
- else
- return false;
- }
- else
- return false;
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- if(isset($_FILES[$key]))
- {
- $this->_fileName=$_FILES[$key]['name'];
- $this->_fileSize=$_FILES[$key]['size'];
- $this->_fileType=$_FILES[$key]['type'];
- $this->_errorCode=$_FILES[$key]['error'];
- $this->_localName=$_FILES[$key]['tmp_name'];
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method calls {@link onFileUpload} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onFileUpload(null);
- }
-
- /**
- * This method is invoked when a file is uploaded during a postback.
- * The method raises <b>OnFileUpload</b> event to fire up the event handler.
- * If you override this method, be sure to call the parent implementation
- * so that the event delegates can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onFileUpload($param)
- {
- $this->raiseEvent('OnFileUpload',$this,$param);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the original file name as the property value to be validated.
- * This method is required by IValidatable property.
- * @return mixed the property value to be validated
- */
- public function getValidationPropertyValue()
- {
- return $this->getFileName();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
-}
-
+<?php
+/**
+ * TFileUpload class file
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFileUpload class
+ *
+ * TFileUpload displays a file upload field on a page. Upon postback,
+ * the text entered into the field will be treated as the name of the file
+ * that will be uploaded to the server. The property {@link getHasFile HasFile}
+ * indicates whether the file upload is successful. If successful, the file
+ * may be obtained by calling {@link saveAs} to save it at a specified place.
+ * You can use {@link getFileName FileName}, {@link getFileType FileType},
+ * {@link getFileSize FileSize} to get the original client-side file name,
+ * the file mime type, and the file size information. If the upload is not
+ * successful, {@link getErrorCode ErrorCode} contains the error code
+ * describing the cause of failure.
+ *
+ * TFileUpload raises {@link onFileUpload OnFileUpload} event if a file is uploaded
+ * (whether it succeeds or not).
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net>, Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFileUpload extends TWebControl implements IPostBackDataHandler, IValidatable
+{
+ /**
+ * Maximum file size (in bytes) allowed to be uploaded, defaults to 1MB.
+ */
+ const MAX_FILE_SIZE=1048576;
+ /**
+ * @var integer the size of the uploaded file (in bytes)
+ */
+ private $_fileSize=0;
+ /**
+ * @var string The original name of the file on the client machine
+ */
+ private $_fileName='';
+ /**
+ * @var string the name of the temporary file storing the uploaded file
+ */
+ private $_localName='';
+ /**
+ * @var string the uploaded file mime type
+ */
+ private $_fileType='';
+ /**
+ * @var integer error code of the current file upload
+ */
+ protected $_errorCode=UPLOAD_ERR_NO_FILE;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the file upload control
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets name attribute to the unique ID of the control.
+ * This method overrides the parent implementation with additional file update control specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $this->getPage()->ensureRenderInForm($this);
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('type','file');
+ $writer->addAttribute('name',$this->getUniqueID());
+ $isEnabled=$this->getEnabled(true);
+ if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Sets Enctype of the form on the page.
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if(($form=$this->getPage()->getForm())!==null)
+ $form->setEnctype('multipart/form-data');
+ $this->getPage()->getClientScript()->registerHiddenField('MAX_FILE_SIZE',$this->getMaxFileSize());
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * @return integer the maximum file size, defaults to 1MB (1048576 bytes).
+ * @see setMaxFileSize
+ */
+ public function getMaxFileSize()
+ {
+ return $this->getViewState('MaxFileSize',self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * Sets the maximum size that a file can be uploaded.
+ * Note, this is an advisory value to the browser. Sets this property with
+ * a reasonably large size to save users the trouble of waiting
+ * for a big file being transferred only to find that it was too big
+ * and the transfer failed.
+ * @param int the maximum upload size allowed for a file.
+ */
+ public function setMaxFileSize($size)
+ {
+ $this->setViewState('MaxFileSize',TPropertyValue::ensureInteger($size),self::MAX_FILE_SIZE);
+ }
+
+ /**
+ * @return string the original full path name of the file on the client machine
+ */
+ public function getFileName()
+ {
+ return $this->_fileName;
+ }
+
+ /**
+ * @return integer the actual size of the uploaded file in bytes
+ */
+ public function getFileSize()
+ {
+ return $this->_fileSize;
+ }
+
+ /**
+ * @return string the MIME-type of the uploaded file (such as "image/gif").
+ * This mime type is not checked on the server side and do not take its value for granted.
+ */
+ public function getFileType()
+ {
+ return $this->_fileType;
+ }
+
+ /**
+ * @return string the local name of the file (where it is after being uploaded).
+ * Note, PHP will delete this file automatically after finishing this round of request.
+ */
+ public function getLocalName()
+ {
+ return $this->_localName;
+ }
+
+ /**
+ * Returns an error code describing the status of this file uploading.
+ * @return integer the error code
+ * @see http://www.php.net/manual/en/features.file-upload.errors.php
+ */
+ public function getErrorCode()
+ {
+ return $this->_errorCode;
+ }
+
+ /**
+ * @return boolean whether the file is uploaded successfully
+ */
+ public function getHasFile()
+ {
+ return $this->_errorCode===UPLOAD_ERR_OK;
+ }
+
+ /**
+ * Saves the uploaded file.
+ * @param string the file name used to save the uploaded file
+ * @param boolean whether to delete the temporary file after saving.
+ * If true, you will not be able to save the uploaded file again.
+ * @return boolean true if the file saving is successful
+ */
+ public function saveAs($fileName,$deleteTempFile=true)
+ {
+ if($this->_errorCode===UPLOAD_ERR_OK)
+ {
+ if($deleteTempFile)
+ return move_uploaded_file($this->_localName,$fileName);
+ else if(is_uploaded_file($this->_localName))
+ return file_put_contents($fileName,file_get_contents($this->_localName))!==false;
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(isset($_FILES[$key]))
+ {
+ $this->_fileName=$_FILES[$key]['name'];
+ $this->_fileSize=$_FILES[$key]['size'];
+ $this->_fileType=$_FILES[$key]['type'];
+ $this->_errorCode=$_FILES[$key]['error'];
+ $this->_localName=$_FILES[$key]['tmp_name'];
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onFileUpload} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onFileUpload(null);
+ }
+
+ /**
+ * This method is invoked when a file is uploaded during a postback.
+ * The method raises <b>OnFileUpload</b> event to fire up the event handler.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event delegates can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onFileUpload($param)
+ {
+ $this->raiseEvent('OnFileUpload',$this,$param);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the original file name as the property value to be validated.
+ * This method is required by IValidatable property.
+ * @return mixed the property value to be validated
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getFileName();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+}
+
diff --git a/framework/Web/UI/WebControls/TFlushOutput.php b/framework/Web/UI/WebControls/TFlushOutput.php
index cc55646d..0ea9b389 100644
--- a/framework/Web/UI/WebControls/TFlushOutput.php
+++ b/framework/Web/UI/WebControls/TFlushOutput.php
@@ -1,86 +1,86 @@
-<?php
-/**
- * TFlushOutput class file
- *
- * @author Berczi Gabor <gabor.berczi@devworx.hu>
- * @link http://www.pradosoft.com/
- * @license http://www.pradosoft.com/license/
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFlushOutput class.
- *
- * TFlushOutput enables forced flushing of the current output buffer
- * at (a) certain point(s) in the page, after rendering of all previous
- * controls has been completed.
- *
- * To use TFlushOutput, simply place it in a template where you want
- * the have the output buffered between the start of the page or the
- * last TFlushOutput to be sent to the client immediately
- * <code>
- * <com:TFlushOutput />
- * </code>
- *
- * You can specify whether you want to keep buffering of the output
- * (if it was enabled) till the next occourence of a <com: TFlushOutput />
- * or the end of the page rendering, or stop buffering, by using the
- * {@link setContinueBuffering ContinueBuffering}.
- *
- * @author Berczi Gabor <gabor.berczi@devworx.hu>
- * @version $Id: TFlushOutput.php $
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TFlushOutput extends TControl
-{
- /**
- * @var boolean whether to continue buffering of output
- */
- private $_continueBuffering=true;
-
-
- /**
- * Constructor.
- */
- public function __construct()
- {
- parent::__construct();
- $this->EnableViewState = false;
- }
-
- /**
- * @return Tells whether buffering of output can continue after this point
- */
- public function getContinueBuffering()
- {
- return $this->_continueBuffering;
- }
-
- /**
- * @param boolean sets whether buffering of output can continue after this point
- */
- public function setContinueBuffering($value)
- {
- $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Flushes the output of all completely rendered controls to the client.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
-//$writer->write('<!-- flush -->');
- // ajax responses can't be parsed by the client side before loaded and returned completely,
- // so don't bother with flushing output somewhere mid-page if refreshing in a callback
- if (!$this->Page->IsCallback)
- {
- $this->Page->flushWriter();
-// $this->Application->flushOutput($this->ContinueBuffering);
- }
- }
-}
-
+<?php
+/**
+ * TFlushOutput class file
+ *
+ * @author Berczi Gabor <gabor.berczi@devworx.hu>
+ * @link http://www.pradosoft.com/
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TFlushOutput.php $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFlushOutput class.
+ *
+ * TFlushOutput enables forced flushing of the current output buffer
+ * at (a) certain point(s) in the page, after rendering of all previous
+ * controls has been completed.
+ *
+ * To use TFlushOutput, simply place it in a template where you want
+ * the have the output buffered between the start of the page or the
+ * last TFlushOutput to be sent to the client immediately
+ * <code>
+ * <com:TFlushOutput />
+ * </code>
+ *
+ * You can specify whether you want to keep buffering of the output
+ * (if it was enabled) till the next occourence of a <com: TFlushOutput />
+ * or the end of the page rendering, or stop buffering, by using the
+ * {@link setContinueBuffering ContinueBuffering}.
+ *
+ * @author Berczi Gabor <gabor.berczi@devworx.hu>
+ * @version $Id: TFlushOutput.php $
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TFlushOutput extends TControl
+{
+ /**
+ * @var boolean whether to continue buffering of output
+ */
+ private $_continueBuffering=true;
+
+
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->EnableViewState = false;
+ }
+
+ /**
+ * @return Tells whether buffering of output can continue after this point
+ */
+ public function getContinueBuffering()
+ {
+ return $this->_continueBuffering;
+ }
+
+ /**
+ * @param boolean sets whether buffering of output can continue after this point
+ */
+ public function setContinueBuffering($value)
+ {
+ $this->_continueBuffering = TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Flushes the output of all completely rendered controls to the client.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+//$writer->write('<!-- flush -->');
+ // ajax responses can't be parsed by the client side before loaded and returned completely,
+ // so don't bother with flushing output somewhere mid-page if refreshing in a callback
+ if (!$this->Page->IsCallback)
+ {
+ $this->Page->flushWriter();
+// $this->Application->flushOutput($this->ContinueBuffering);
+ }
+ }
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TFont.php b/framework/Web/UI/WebControls/TFont.php
index 4da42508..771b6a4e 100644
--- a/framework/Web/UI/WebControls/TFont.php
+++ b/framework/Web/UI/WebControls/TFont.php
@@ -1,318 +1,318 @@
-<?php
-/**
- * TFont class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TFont class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TFont class
- *
- * TFont encapsulates the CSS style fields related with font settings.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TFont extends TComponent
-{
- /**
- * Bits indicating the font states.
- */
- const IS_BOLD=0x01;
- const IS_ITALIC=0x02;
- const IS_OVERLINE=0x04;
- const IS_STRIKEOUT=0x08;
- const IS_UNDERLINE=0x10;
-
- /**
- * Bits indicating whether particular font states are changed.
- */
- const IS_SET_BOLD=0x01000;
- const IS_SET_ITALIC=0x02000;
- const IS_SET_OVERLINE=0x04000;
- const IS_SET_STRIKEOUT=0x08000;
- const IS_SET_UNDERLINE=0x10000;
- const IS_SET_SIZE=0x20000;
- const IS_SET_NAME=0x40000;
-
- /**
- * @var integer bits representing various states
- */
- private $_flags=0;
- /**
- * @var string font name
- */
- private $_name='';
- /**
- * @var string font size
- */
- private $_size='';
-
- /**
- * @return boolean whether the font is in bold face. Defaults to false.
- */
- public function getBold()
- {
- return ($this->_flags & self::IS_BOLD)!==0;
- }
-
- /**
- * @param boolean whether the font is in bold face
- */
- public function setBold($value)
- {
- $this->_flags |= self::IS_SET_BOLD;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_BOLD;
- else
- $this->_flags &= ~self::IS_BOLD;
- }
-
- /**
- * @return boolean whether the font is in italic face. Defaults to false.
- */
- public function getItalic()
- {
- return ($this->_flags & self::IS_ITALIC)!==0;
- }
-
- /**
- * @param boolean whether the font is italic
- */
- public function setItalic($value)
- {
- $this->_flags |= self::IS_SET_ITALIC;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_ITALIC;
- else
- $this->_flags &= ~self::IS_ITALIC;
- }
-
- /**
- * @return boolean whether the font is overlined. Defaults to false.
- */
- public function getOverline()
- {
- return ($this->_flags & self::IS_OVERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is overlined
- */
- public function setOverline($value)
- {
- $this->_flags |= self::IS_SET_OVERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_OVERLINE;
- else
- $this->_flags &= ~self::IS_OVERLINE;
- }
-
- /**
- * @return string the font size
- */
- public function getSize()
- {
- return $this->_size;
- }
-
- /**
- * @param string the font size
- */
- public function setSize($value)
- {
- $this->_flags |= self::IS_SET_SIZE;
- $this->_size=$value;
- }
-
- /**
- * @return boolean whether the font is strikeout. Defaults to false.
- */
- public function getStrikeout()
- {
- return ($this->_flags & self::IS_STRIKEOUT)!==0;
- }
-
- /**
- * @param boolean whether the font is strikeout
- */
- public function setStrikeout($value)
- {
- $this->_flags |= self::IS_SET_STRIKEOUT;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_STRIKEOUT;
- else
- $this->_flags &= ~self::IS_STRIKEOUT;
- }
-
- /**
- * @return boolean whether the font is underlined. Defaults to false.
- */
- public function getUnderline()
- {
- return ($this->_flags & self::IS_UNDERLINE)!==0;
- }
-
- /**
- * @param boolean whether the font is underlined
- */
- public function setUnderline($value)
- {
- $this->_flags |= self::IS_SET_UNDERLINE;
- if(TPropertyValue::ensureBoolean($value))
- $this->_flags |= self::IS_UNDERLINE;
- else
- $this->_flags &= ~self::IS_UNDERLINE;
- }
-
- /**
- * @return string the font name (family)
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string the font name (family)
- */
- public function setName($value)
- {
- $this->_flags |= self::IS_SET_NAME;
- $this->_name=$value;
- }
-
- /**
- * @return boolean whether the font is empty
- */
- public function getIsEmpty()
- {
- return !$this->_flags;
- }
-
- /**
- * Clears up the font.
- */
- public function reset()
- {
- $this->_flags=0;
- $this->_name='';
- $this->_size='';
- }
-
- /**
- * Merges the font with a new one.
- * If a font field is not set in the font, it will be overwritten with
- * the new one.
- * @param TFont the new font
- */
- public function mergeWith($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
- $this->setBold($font->getBold());
- if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
- $this->setItalic($font->getItalic());
- if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
- $this->setOverline($font->getOverline());
- if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
- $this->setStrikeout($font->getStrikeout());
- if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
- $this->setUnderline($font->getUnderline());
- if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
- $this->setSize($font->getSize());
- if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
- $this->setName($font->getName());
- }
-
- /**
- * Copies the fields in a new font to this font.
- * If a font field is set in the new font, the corresponding field
- * in this font will be overwritten.
- * @param TFont the new font
- */
- public function copyFrom($font)
- {
- if($font===null || $font->_flags===0)
- return;
- if($font->_flags & self::IS_SET_BOLD)
- $this->setBold($font->getBold());
- if($font->_flags & self::IS_SET_ITALIC)
- $this->setItalic($font->getItalic());
- if($font->_flags & self::IS_SET_OVERLINE)
- $this->setOverline($font->getOverline());
- if($font->_flags & self::IS_SET_STRIKEOUT)
- $this->setStrikeout($font->getStrikeout());
- if($font->_flags & self::IS_SET_UNDERLINE)
- $this->setUnderline($font->getUnderline());
- if($font->_flags & self::IS_SET_SIZE)
- $this->setSize($font->getSize());
- if($font->_flags & self::IS_SET_NAME)
- $this->setName($font->getName());
- }
-
- /**
- * @return string the font in a css style string representation.
- */
- public function toString()
- {
- if($this->_flags===0)
- return '';
- $str='';
- if($this->_flags & self::IS_SET_BOLD)
- $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
- if($this->_flags & self::IS_SET_ITALIC)
- $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $str.='text-decoration:'.$textDec.';';
- if($this->_size!=='')
- $str.='font-size:'.$this->_size.';';
- if($this->_name!=='')
- $str.='font-family:'.$this->_name.';';
- return $str;
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if($this->_flags===0)
- return;
- if($this->_flags & self::IS_SET_BOLD)
- $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
- if($this->_flags & self::IS_SET_ITALIC)
- $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
- $textDec='';
- if($this->_flags & self::IS_UNDERLINE)
- $textDec.='underline';
- if($this->_flags & self::IS_OVERLINE)
- $textDec.=' overline';
- if($this->_flags & self::IS_STRIKEOUT)
- $textDec.=' line-through';
- $textDec=ltrim($textDec);
- if($textDec!=='')
- $writer->addStyleAttribute('text-decoration',$textDec);
- if($this->_size!=='')
- $writer->addStyleAttribute('font-size',$this->_size);
- if($this->_name!=='')
- $writer->addStyleAttribute('font-family',$this->_name);
- }
-}
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TFont class
+ *
+ * TFont encapsulates the CSS style fields related with font settings.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TFont extends TComponent
+{
+ /**
+ * Bits indicating the font states.
+ */
+ const IS_BOLD=0x01;
+ const IS_ITALIC=0x02;
+ const IS_OVERLINE=0x04;
+ const IS_STRIKEOUT=0x08;
+ const IS_UNDERLINE=0x10;
+
+ /**
+ * Bits indicating whether particular font states are changed.
+ */
+ const IS_SET_BOLD=0x01000;
+ const IS_SET_ITALIC=0x02000;
+ const IS_SET_OVERLINE=0x04000;
+ const IS_SET_STRIKEOUT=0x08000;
+ const IS_SET_UNDERLINE=0x10000;
+ const IS_SET_SIZE=0x20000;
+ const IS_SET_NAME=0x40000;
+
+ /**
+ * @var integer bits representing various states
+ */
+ private $_flags=0;
+ /**
+ * @var string font name
+ */
+ private $_name='';
+ /**
+ * @var string font size
+ */
+ private $_size='';
+
+ /**
+ * @return boolean whether the font is in bold face. Defaults to false.
+ */
+ public function getBold()
+ {
+ return ($this->_flags & self::IS_BOLD)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is in bold face
+ */
+ public function setBold($value)
+ {
+ $this->_flags |= self::IS_SET_BOLD;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_BOLD;
+ else
+ $this->_flags &= ~self::IS_BOLD;
+ }
+
+ /**
+ * @return boolean whether the font is in italic face. Defaults to false.
+ */
+ public function getItalic()
+ {
+ return ($this->_flags & self::IS_ITALIC)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is italic
+ */
+ public function setItalic($value)
+ {
+ $this->_flags |= self::IS_SET_ITALIC;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_ITALIC;
+ else
+ $this->_flags &= ~self::IS_ITALIC;
+ }
+
+ /**
+ * @return boolean whether the font is overlined. Defaults to false.
+ */
+ public function getOverline()
+ {
+ return ($this->_flags & self::IS_OVERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is overlined
+ */
+ public function setOverline($value)
+ {
+ $this->_flags |= self::IS_SET_OVERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_OVERLINE;
+ else
+ $this->_flags &= ~self::IS_OVERLINE;
+ }
+
+ /**
+ * @return string the font size
+ */
+ public function getSize()
+ {
+ return $this->_size;
+ }
+
+ /**
+ * @param string the font size
+ */
+ public function setSize($value)
+ {
+ $this->_flags |= self::IS_SET_SIZE;
+ $this->_size=$value;
+ }
+
+ /**
+ * @return boolean whether the font is strikeout. Defaults to false.
+ */
+ public function getStrikeout()
+ {
+ return ($this->_flags & self::IS_STRIKEOUT)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is strikeout
+ */
+ public function setStrikeout($value)
+ {
+ $this->_flags |= self::IS_SET_STRIKEOUT;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_STRIKEOUT;
+ else
+ $this->_flags &= ~self::IS_STRIKEOUT;
+ }
+
+ /**
+ * @return boolean whether the font is underlined. Defaults to false.
+ */
+ public function getUnderline()
+ {
+ return ($this->_flags & self::IS_UNDERLINE)!==0;
+ }
+
+ /**
+ * @param boolean whether the font is underlined
+ */
+ public function setUnderline($value)
+ {
+ $this->_flags |= self::IS_SET_UNDERLINE;
+ if(TPropertyValue::ensureBoolean($value))
+ $this->_flags |= self::IS_UNDERLINE;
+ else
+ $this->_flags &= ~self::IS_UNDERLINE;
+ }
+
+ /**
+ * @return string the font name (family)
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string the font name (family)
+ */
+ public function setName($value)
+ {
+ $this->_flags |= self::IS_SET_NAME;
+ $this->_name=$value;
+ }
+
+ /**
+ * @return boolean whether the font is empty
+ */
+ public function getIsEmpty()
+ {
+ return !$this->_flags;
+ }
+
+ /**
+ * Clears up the font.
+ */
+ public function reset()
+ {
+ $this->_flags=0;
+ $this->_name='';
+ $this->_size='';
+ }
+
+ /**
+ * Merges the font with a new one.
+ * If a font field is not set in the font, it will be overwritten with
+ * the new one.
+ * @param TFont the new font
+ */
+ public function mergeWith($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD))
+ $this->setBold($font->getBold());
+ if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC))
+ $this->setItalic($font->getItalic());
+ if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE))
+ $this->setOverline($font->getOverline());
+ if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT))
+ $this->setStrikeout($font->getStrikeout());
+ if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE))
+ $this->setUnderline($font->getUnderline());
+ if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE))
+ $this->setSize($font->getSize());
+ if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME))
+ $this->setName($font->getName());
+ }
+
+ /**
+ * Copies the fields in a new font to this font.
+ * If a font field is set in the new font, the corresponding field
+ * in this font will be overwritten.
+ * @param TFont the new font
+ */
+ public function copyFrom($font)
+ {
+ if($font===null || $font->_flags===0)
+ return;
+ if($font->_flags & self::IS_SET_BOLD)
+ $this->setBold($font->getBold());
+ if($font->_flags & self::IS_SET_ITALIC)
+ $this->setItalic($font->getItalic());
+ if($font->_flags & self::IS_SET_OVERLINE)
+ $this->setOverline($font->getOverline());
+ if($font->_flags & self::IS_SET_STRIKEOUT)
+ $this->setStrikeout($font->getStrikeout());
+ if($font->_flags & self::IS_SET_UNDERLINE)
+ $this->setUnderline($font->getUnderline());
+ if($font->_flags & self::IS_SET_SIZE)
+ $this->setSize($font->getSize());
+ if($font->_flags & self::IS_SET_NAME)
+ $this->setName($font->getName());
+ }
+
+ /**
+ * @return string the font in a css style string representation.
+ */
+ public function toString()
+ {
+ if($this->_flags===0)
+ return '';
+ $str='';
+ if($this->_flags & self::IS_SET_BOLD)
+ $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;');
+ if($this->_flags & self::IS_SET_ITALIC)
+ $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;');
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $str.='text-decoration:'.$textDec.';';
+ if($this->_size!=='')
+ $str.='font-size:'.$this->_size.';';
+ if($this->_name!=='')
+ $str.='font-family:'.$this->_name.';';
+ return $str;
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if($this->_flags===0)
+ return;
+ if($this->_flags & self::IS_SET_BOLD)
+ $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal'));
+ if($this->_flags & self::IS_SET_ITALIC)
+ $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal'));
+ $textDec='';
+ if($this->_flags & self::IS_UNDERLINE)
+ $textDec.='underline';
+ if($this->_flags & self::IS_OVERLINE)
+ $textDec.=' overline';
+ if($this->_flags & self::IS_STRIKEOUT)
+ $textDec.=' line-through';
+ $textDec=ltrim($textDec);
+ if($textDec!=='')
+ $writer->addStyleAttribute('text-decoration',$textDec);
+ if($this->_size!=='')
+ $writer->addStyleAttribute('font-size',$this->_size);
+ if($this->_name!=='')
+ $writer->addStyleAttribute('font-family',$this->_name);
+ }
+}
diff --git a/framework/Web/UI/WebControls/THead.php b/framework/Web/UI/WebControls/THead.php
index c0042c22..7966f2d3 100644
--- a/framework/Web/UI/WebControls/THead.php
+++ b/framework/Web/UI/WebControls/THead.php
@@ -1,377 +1,377 @@
-<?php
-/**
- * THead class file
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI
- */
-
-/**
- * THead class
- *
- * THead displays a head element on a page. It displays the content
- * enclosed in its body and the page title set by the
- * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
- * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
- * {@link TClientScriptManager::registerHeadJavaScript}, and
- * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
- * in the head.
- * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
- * property. You can add a meta object to the collection in code dynamically,
- * or add it in template using the following syntax,
- * <code>
- * <com:THead>
- * <com:TMetaTag HttpEquiv="Pragma" Content="no-cache" />
- * <com:TMetaTag Name="keywords" Content="Prado" />
- * </com:THead>
- * </code>
- *
- * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
- * the THead control currently on the page. A page can have at most one THead
- * control. Although not required, it is recommended to place a THead on your page.
- * Without a THead on the page, stylesheets and javascripts in the current page
- * theme will not be rendered.
- *
- * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0
- */
-class THead extends TControl
-{
- /**
- * @var TList list of meta name tags to be loaded by {@link THead}
- */
- private $_metaTags=null;
-
- /**
- * Registers the head control with the current page.
- * This method is invoked when the control enters 'Init' stage.
- * The method raises 'Init' event.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->getPage()->setHead($this);
- }
-
- /**
- * Processes an object that is created during parsing template.
- * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
- * collection of the head control.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- */
- public function addParsedObject($object)
- {
- if($object instanceof TMetaTag)
- $this->getMetaTags()->add($object);
- else
- parent::addParsedObject($object);
- }
-
- /**
- * @return string the page title.
- */
- public function getTitle()
- {
- return $this->getViewState('Title','');
- }
-
- /**
- * Sets the page title.
- * This title will be rendered only if the {@link TPage::getTitle Title} property
- * of the page is empty.
- * @param string the page title.
- */
- public function setTitle($value)
- {
- $this->setViewState('Title',$value,'');
- }
-
- /**
- * @return string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. Defaults to ''.
- */
- public function getBaseUrl()
- {
- return $this->getViewState('BaseUrl','');
- }
-
- /**
- * @param string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag.
- */
- public function setBaseUrl($url)
- {
- $this->setViewState('BaseUrl',$url,'');
- }
-
- /**
- * @return string the URL for the shortcut icon of the page. Defaults to ''.
- */
- public function getShortcutIcon()
- {
- return $this->getViewState('ShortcutIcon','');
- }
-
- /**
- * @param string the URL for the shortcut icon of the page.
- */
- public function setShortcutIcon($url)
- {
- $this->setViewState('ShortcutIcon',$url,'');
- }
-
- /**
- * @return TMetaTagCollection meta tag collection
- */
- public function getMetaTags()
- {
- if(($metaTags=$this->getViewState('MetaTags',null))===null)
- {
- $metaTags=new TMetaTagCollection;
- $this->setViewState('MetaTags',$metaTags,null);
- }
- return $metaTags;
- }
-
- /**
- * Renders the head control.
- * @param THtmlWriter the writer for rendering purpose.
- */
- public function render($writer)
- {
- $page=$this->getPage();
- $title=$this->getTitle();
- $writer->write("<head>\n<title>".THttpUtility::htmlEncode($title)."</title>\n");
- if(($baseUrl=$this->getBaseUrl())!=='')
- $writer->write('<base href="'.$baseUrl."\" />\n");
- if(($icon=$this->getShortcutIcon())!=='')
- $writer->write('<link rel="shortcut icon" href="'.$icon."\" />\n");
-
- if(($metaTags=$this->getMetaTags())!==null)
- {
- foreach($metaTags as $metaTag)
- {
- $metaTag->render($writer);
- $writer->writeLine();
- }
- }
- $cs=$page->getClientScript();
- $cs->renderStyleSheetFiles($writer);
- $cs->renderStyleSheets($writer);
- if($page->getClientSupportsJavaScript())
- {
- $cs->renderHeadScriptFiles($writer);
- $cs->renderHeadScripts($writer);
- }
- parent::render($writer);
- $writer->write("</head>\n");
- }
-}
-
-/**
- * TMetaTag class.
- *
- * TMetaTag represents a meta tag appearing in a page head section.
- * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
- * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
- * properties, which correspond to id, http-equiv, name, content, and scheme
- * attributes for a meta tag, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTag extends TComponent
-{
- /**
- * @var string id of the meta tag
- */
- private $_id='';
- /**
- * @var string http-equiv attribute of the meta tag
- */
- private $_httpEquiv='';
- /**
- * @var string name attribute of the meta tag
- */
- private $_name='';
- /**
- * @var string content attribute of the meta tag
- */
- private $_content='';
- /**
- * @var string scheme attribute of the meta tag
- */
- private $_scheme='';
-
- /**
- * @return string id of the meta tag
- */
- public function getID()
- {
- return $this->_id;
- }
-
- /**
- * @param string id of the meta tag
- */
- public function setID($value)
- {
- $this->_id=$value;
- }
-
- /**
- * @return string http-equiv attribute of the meta tag
- */
- public function getHttpEquiv()
- {
- return $this->_httpEquiv;
- }
-
- /**
- * @param string http-equiv attribute of the meta tag
- */
- public function setHttpEquiv($value)
- {
- $this->_httpEquiv=$value;
- }
-
- /**
- * @return string name attribute of the meta tag
- */
- public function getName()
- {
- return $this->_name;
- }
-
- /**
- * @param string name attribute of the meta tag
- */
- public function setName($value)
- {
- $this->_name=$value;
- }
-
- /**
- * @return string content attribute of the meta tag
- */
- public function getContent()
- {
- return $this->_content;
- }
-
- /**
- * @param string content attribute of the meta tag
- */
- public function setContent($value)
- {
- $this->_content=$value;
- }
-
- /**
- * @return string scheme attribute of the meta tag
- */
- public function getScheme()
- {
- return $this->_scheme;
- }
-
- /**
- * @param string scheme attribute of the meta tag
- */
- public function setScheme($value)
- {
- $this->_scheme=$value;
- }
-
- /**
- * Renders the meta tag.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_id!=='')
- $writer->addAttribute('id',$this->_id);
- if($this->_name!=='')
- $writer->addAttribute('name',$this->_name);
- if($this->_httpEquiv!=='')
- $writer->addAttribute('http-equiv',$this->_httpEquiv);
- if($this->_scheme!=='')
- $writer->addAttribute('scheme',$this->_scheme);
- $writer->addAttribute('content',$this->_content);
- $writer->renderBeginTag('meta');
- $writer->renderEndTag();
- }
-}
-
-
-/**
- * TMetaTagCollection class
- *
- * TMetaTagCollection represents a collection of meta tags
- * contained in a {@link THead} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMetaTagCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing type
- * check on the item being added.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TMetaTag)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
- }
-
- /**
- * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
- * @param string the ID of the meta tag to be looked for
- * @return integer the index of the meta tag found, -1 if not found.
- */
- public function findIndexByID($id)
- {
- $index=0;
- foreach($this as $item)
- {
- if($item->getID()===$id)
- return $index;
- $index++;
- }
- return -1;
- }
-
- /**
- * Finds the item whose value is the one being looked for.
- * @param string the id of the meta tag to be looked for
- * @return TMetaTag the meta tag found, null if not found.
- */
- public function findMetaTagByID($id)
- {
- if(($index=$this->findIndexByID($id))>=0)
- return $this->itemAt($index);
- else
- return null;
- }
-}
-
-?>
+<?php
+/**
+ * THead class file
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI
+ */
+
+/**
+ * THead class
+ *
+ * THead displays a head element on a page. It displays the content
+ * enclosed in its body and the page title set by the
+ * {@link setTitle Title} property. In addition, stylesheets and JavaScripts registered via
+ * {@link TClientScriptManager::registerStyleSheet}, {@link TClientScriptManager::registerStyleSheetFile}
+ * {@link TClientScriptManager::registerHeadJavaScript}, and
+ * {@link TClientScriptManager::registerHeadJavaScriptFile} will also be displayed
+ * in the head.
+ * THead also manages and displays meta tags through its {@link getMetaTags MetaTags}
+ * property. You can add a meta object to the collection in code dynamically,
+ * or add it in template using the following syntax,
+ * <code>
+ * <com:THead>
+ * <com:TMetaTag HttpEquiv="Pragma" Content="no-cache" />
+ * <com:TMetaTag Name="keywords" Content="Prado" />
+ * </com:THead>
+ * </code>
+ *
+ * Note, {@link TPage} has a property {@link TPage::getHead Head} that refers to
+ * the THead control currently on the page. A page can have at most one THead
+ * control. Although not required, it is recommended to place a THead on your page.
+ * Without a THead on the page, stylesheets and javascripts in the current page
+ * theme will not be rendered.
+ *
+ * @author Marcus Nyeholt <tanus@users.sourceforge.net> and Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0
+ */
+class THead extends TControl
+{
+ /**
+ * @var TList list of meta name tags to be loaded by {@link THead}
+ */
+ private $_metaTags=null;
+
+ /**
+ * Registers the head control with the current page.
+ * This method is invoked when the control enters 'Init' stage.
+ * The method raises 'Init' event.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->getPage()->setHead($this);
+ }
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method adds TMetaTag components into the {@link getMetaTags MetaTags}
+ * collection of the head control.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TMetaTag)
+ $this->getMetaTags()->add($object);
+ else
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * @return string the page title.
+ */
+ public function getTitle()
+ {
+ return $this->getViewState('Title','');
+ }
+
+ /**
+ * Sets the page title.
+ * This title will be rendered only if the {@link TPage::getTitle Title} property
+ * of the page is empty.
+ * @param string the page title.
+ */
+ public function setTitle($value)
+ {
+ $this->setViewState('Title',$value,'');
+ }
+
+ /**
+ * @return string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag. Defaults to ''.
+ */
+ public function getBaseUrl()
+ {
+ return $this->getViewState('BaseUrl','');
+ }
+
+ /**
+ * @param string base URL of the page. This URL is rendered as the 'href' attribute of <base> tag.
+ */
+ public function setBaseUrl($url)
+ {
+ $this->setViewState('BaseUrl',$url,'');
+ }
+
+ /**
+ * @return string the URL for the shortcut icon of the page. Defaults to ''.
+ */
+ public function getShortcutIcon()
+ {
+ return $this->getViewState('ShortcutIcon','');
+ }
+
+ /**
+ * @param string the URL for the shortcut icon of the page.
+ */
+ public function setShortcutIcon($url)
+ {
+ $this->setViewState('ShortcutIcon',$url,'');
+ }
+
+ /**
+ * @return TMetaTagCollection meta tag collection
+ */
+ public function getMetaTags()
+ {
+ if(($metaTags=$this->getViewState('MetaTags',null))===null)
+ {
+ $metaTags=new TMetaTagCollection;
+ $this->setViewState('MetaTags',$metaTags,null);
+ }
+ return $metaTags;
+ }
+
+ /**
+ * Renders the head control.
+ * @param THtmlWriter the writer for rendering purpose.
+ */
+ public function render($writer)
+ {
+ $page=$this->getPage();
+ $title=$this->getTitle();
+ $writer->write("<head>\n<title>".THttpUtility::htmlEncode($title)."</title>\n");
+ if(($baseUrl=$this->getBaseUrl())!=='')
+ $writer->write('<base href="'.$baseUrl."\" />\n");
+ if(($icon=$this->getShortcutIcon())!=='')
+ $writer->write('<link rel="shortcut icon" href="'.$icon."\" />\n");
+
+ if(($metaTags=$this->getMetaTags())!==null)
+ {
+ foreach($metaTags as $metaTag)
+ {
+ $metaTag->render($writer);
+ $writer->writeLine();
+ }
+ }
+ $cs=$page->getClientScript();
+ $cs->renderStyleSheetFiles($writer);
+ $cs->renderStyleSheets($writer);
+ if($page->getClientSupportsJavaScript())
+ {
+ $cs->renderHeadScriptFiles($writer);
+ $cs->renderHeadScripts($writer);
+ }
+ parent::render($writer);
+ $writer->write("</head>\n");
+ }
+}
+
+/**
+ * TMetaTag class.
+ *
+ * TMetaTag represents a meta tag appearing in a page head section.
+ * You can set its {@link setID ID}, {@link setHttpEquiv HttpEquiv},
+ * {@link setName Name}, {@link setContent Content}, {@link setScheme Scheme}
+ * properties, which correspond to id, http-equiv, name, content, and scheme
+ * attributes for a meta tag, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTag extends TComponent
+{
+ /**
+ * @var string id of the meta tag
+ */
+ private $_id='';
+ /**
+ * @var string http-equiv attribute of the meta tag
+ */
+ private $_httpEquiv='';
+ /**
+ * @var string name attribute of the meta tag
+ */
+ private $_name='';
+ /**
+ * @var string content attribute of the meta tag
+ */
+ private $_content='';
+ /**
+ * @var string scheme attribute of the meta tag
+ */
+ private $_scheme='';
+
+ /**
+ * @return string id of the meta tag
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * @param string id of the meta tag
+ */
+ public function setID($value)
+ {
+ $this->_id=$value;
+ }
+
+ /**
+ * @return string http-equiv attribute of the meta tag
+ */
+ public function getHttpEquiv()
+ {
+ return $this->_httpEquiv;
+ }
+
+ /**
+ * @param string http-equiv attribute of the meta tag
+ */
+ public function setHttpEquiv($value)
+ {
+ $this->_httpEquiv=$value;
+ }
+
+ /**
+ * @return string name attribute of the meta tag
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * @param string name attribute of the meta tag
+ */
+ public function setName($value)
+ {
+ $this->_name=$value;
+ }
+
+ /**
+ * @return string content attribute of the meta tag
+ */
+ public function getContent()
+ {
+ return $this->_content;
+ }
+
+ /**
+ * @param string content attribute of the meta tag
+ */
+ public function setContent($value)
+ {
+ $this->_content=$value;
+ }
+
+ /**
+ * @return string scheme attribute of the meta tag
+ */
+ public function getScheme()
+ {
+ return $this->_scheme;
+ }
+
+ /**
+ * @param string scheme attribute of the meta tag
+ */
+ public function setScheme($value)
+ {
+ $this->_scheme=$value;
+ }
+
+ /**
+ * Renders the meta tag.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_id!=='')
+ $writer->addAttribute('id',$this->_id);
+ if($this->_name!=='')
+ $writer->addAttribute('name',$this->_name);
+ if($this->_httpEquiv!=='')
+ $writer->addAttribute('http-equiv',$this->_httpEquiv);
+ if($this->_scheme!=='')
+ $writer->addAttribute('scheme',$this->_scheme);
+ $writer->addAttribute('content',$this->_content);
+ $writer->renderBeginTag('meta');
+ $writer->renderEndTag();
+ }
+}
+
+
+/**
+ * TMetaTagCollection class
+ *
+ * TMetaTagCollection represents a collection of meta tags
+ * contained in a {@link THead} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMetaTagCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing type
+ * check on the item being added.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a {@link TMetaTag}
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TMetaTag)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('metatagcollection_metatag_invalid');
+ }
+
+ /**
+ * Finds the lowest cardinal index of the meta tag whose id is the one being looked for.
+ * @param string the ID of the meta tag to be looked for
+ * @return integer the index of the meta tag found, -1 if not found.
+ */
+ public function findIndexByID($id)
+ {
+ $index=0;
+ foreach($this as $item)
+ {
+ if($item->getID()===$id)
+ return $index;
+ $index++;
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the item whose value is the one being looked for.
+ * @param string the id of the meta tag to be looked for
+ * @return TMetaTag the meta tag found, null if not found.
+ */
+ public function findMetaTagByID($id)
+ {
+ if(($index=$this->findIndexByID($id))>=0)
+ return $this->itemAt($index);
+ else
+ return null;
+ }
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/THiddenField.php b/framework/Web/UI/WebControls/THiddenField.php
index ac8ddfff..ec330d54 100644
--- a/framework/Web/UI/WebControls/THiddenField.php
+++ b/framework/Web/UI/WebControls/THiddenField.php
@@ -1,117 +1,117 @@
-<?php
-/**
- * THiddenField class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.xisc.com/
+<?php
+/**
+ * THiddenField class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.xisc.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THiddenField class
- *
- * THiddenField displays a hidden input field on a Web page.
- * The value of the input field can be accessed via {@link getValue Value} property.
- * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
- * event will be raised.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
-{
- private $_dataChanged=false;
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THiddenField class
+ *
+ * THiddenField displays a hidden input field on a Web page.
+ * The value of the input field can be accessed via {@link getValue Value} property.
+ * If upon postback the value is changed, a {@link onValueChanged OnValueChanged}
+ * event will be raised.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THiddenField extends TControl implements IPostBackDataHandler, IValidatable, IDataRenderer
+{
+ private $_dataChanged=false;
private $_isValid=true;
-
- /**
- * @return string tag name of the hidden field.
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * Sets focus to this control.
- * This method overrides the parent implementation by forbidding setting focus to this control.
- */
- public function focus()
- {
- throw new TNotSupportedException('hiddenfield_focus_unsupported');
- }
-
- /**
- * Renders the control.
- * This method overrides the parent implementation by rendering
- * the hidden field input element.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- $uniqueID=$this->getUniqueID();
- $this->getPage()->ensureRenderInForm($this);
- $writer->addAttribute('type','hidden');
- if($uniqueID!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getID()!=='')
- $writer->addAttribute('id',$this->getClientID());
- if(($value=$this->getValue())!=='')
- $writer->addAttribute('value',$value);
-
- if($this->getHasAttributes())
- {
- foreach($this->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
-
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Loads hidden field data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=$values[$key];
- if($value===$this->getValue())
- return false;
- else
- {
- $this->setValue($value);
- return $this->_dataChanged=true;
- }
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getValue();
- }
-
+
+ /**
+ * @return string tag name of the hidden field.
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * Sets focus to this control.
+ * This method overrides the parent implementation by forbidding setting focus to this control.
+ */
+ public function focus()
+ {
+ throw new TNotSupportedException('hiddenfield_focus_unsupported');
+ }
+
+ /**
+ * Renders the control.
+ * This method overrides the parent implementation by rendering
+ * the hidden field input element.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $uniqueID=$this->getUniqueID();
+ $this->getPage()->ensureRenderInForm($this);
+ $writer->addAttribute('type','hidden');
+ if($uniqueID!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getID()!=='')
+ $writer->addAttribute('id',$this->getClientID());
+ if(($value=$this->getValue())!=='')
+ $writer->addAttribute('value',$value);
+
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Loads hidden field data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=$values[$key];
+ if($value===$this->getValue())
+ return false;
+ else
+ {
+ $this->setValue($value);
+ return $this->_dataChanged=true;
+ }
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getValue();
+ }
+
/**
* Returns true if this control validated successfully.
* Defaults to true.
@@ -129,96 +129,96 @@ class THiddenField extends TControl implements IPostBackDataHandler, IValidatabl
$this->_isValid=TPropertyValue::ensureBoolean($value);
}
- /**
- * Raises postdata changed event.
- * This method calls {@link onValueChanged} method.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onValueChanged(null);
- }
-
- /**
- * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
- * The method raises 'OnValueChanged' event to fire up the event delegates.
- * If you override this method, be sure to call the parent implementation
- * so that the attached event handlers can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onValueChanged($param)
- {
- $this->raiseEvent('OnValueChanged',$this,$param);
- }
-
- /**
- * @return string the value of the THiddenField
- */
- public function getValue()
- {
- return $this->getViewState('Value','');
- }
-
- /**
- * Sets the value of the THiddenField
- * @param string the value to be set
- */
- public function setValue($value)
- {
- $this->setViewState('Value',$value,'');
- }
-
- /**
- * Returns the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getValue()}.
- * @return string value of the hidden field
- * @see getValue
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getValue();
- }
-
- /**
- * Sets the value of the hidden field.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setValue()}.
- * @param string value of the hidden field
- * @see setValue
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setValue($value);
- }
-
-
- /**
- * @return boolean whether theming is enabled for this control. Defaults to false.
- */
- public function getEnableTheming()
- {
- return false;
- }
-
- /**
- * @param boolean whether theming is enabled for this control.
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setEnableTheming($value)
- {
- throw new TNotSupportedException('hiddenfield_theming_unsupported');
- }
-
- /**
- * @param string Skin ID
- * @throws TNotSupportedException This method is always thrown when calling this method.
- */
- public function setSkinID($value)
- {
- throw new TNotSupportedException('hiddenfield_skinid_unsupported');
- }
-}
-
+ /**
+ * Raises postdata changed event.
+ * This method calls {@link onValueChanged} method.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onValueChanged(null);
+ }
+
+ /**
+ * This method is invoked when the value of the {@link getValue Value} property changes between posts to the server.
+ * The method raises 'OnValueChanged' event to fire up the event delegates.
+ * If you override this method, be sure to call the parent implementation
+ * so that the attached event handlers can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onValueChanged($param)
+ {
+ $this->raiseEvent('OnValueChanged',$this,$param);
+ }
+
+ /**
+ * @return string the value of the THiddenField
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value','');
+ }
+
+ /**
+ * Sets the value of the THiddenField
+ * @param string the value to be set
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value',$value,'');
+ }
+
+ /**
+ * Returns the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getValue()}.
+ * @return string value of the hidden field
+ * @see getValue
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Sets the value of the hidden field.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setValue()}.
+ * @param string value of the hidden field
+ * @see setValue
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setValue($value);
+ }
+
+
+ /**
+ * @return boolean whether theming is enabled for this control. Defaults to false.
+ */
+ public function getEnableTheming()
+ {
+ return false;
+ }
+
+ /**
+ * @param boolean whether theming is enabled for this control.
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setEnableTheming($value)
+ {
+ throw new TNotSupportedException('hiddenfield_theming_unsupported');
+ }
+
+ /**
+ * @param string Skin ID
+ * @throws TNotSupportedException This method is always thrown when calling this method.
+ */
+ public function setSkinID($value)
+ {
+ throw new TNotSupportedException('hiddenfield_skinid_unsupported');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/THtmlElement.php b/framework/Web/UI/WebControls/THtmlElement.php
index 3889ee50..29cd0057 100644
--- a/framework/Web/UI/WebControls/THtmlElement.php
+++ b/framework/Web/UI/WebControls/THtmlElement.php
@@ -1,68 +1,68 @@
-<?php
-/**
- * THtmlElement class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TWebControl');
-
-/**
- * THtmlElement class.
- *
- * THtmlElement represents a generic HTML element whose tag name is specified
- * via {@link setTagName TagName} property. Because THtmlElement extends from
- * {@link TWebControl}, it enjoys all its functionalities.
- *
- * To change the default tag your subclass should override {@link getDefaultTagName}
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @author Brad Anderson <javalizard@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-class THtmlElement extends TWebControl
-{
- /**
- * @var the tag of this element
- */
- private $_tagName=null;
-
- /**
- * @return string the tag name of this control. Defaults to 'span'.
- */
- public function getTagName()
- {
- return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
- }
-
- /**
- * @param string the tag name of this control.
- */
- public function setTagName($value)
- {
- $this->_tagName=TPropertyValue::ensureString($value);
- }
-
- /**
- * This is the default tag when no other is specified
- * @return string the default tag
- */
- public function getDefaultTagName() {
- return 'span';
- }
-
- /**
- * This tells you if this TagName has deviated from the original
- * @return boolean true if TagName has deviated from the default.
- */
- public function getIsMutated() {
- return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
- }
-}
+<?php
+/**
+ * THtmlElement class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TWebControl');
+
+/**
+ * THtmlElement class.
+ *
+ * THtmlElement represents a generic HTML element whose tag name is specified
+ * via {@link setTagName TagName} property. Because THtmlElement extends from
+ * {@link TWebControl}, it enjoys all its functionalities.
+ *
+ * To change the default tag your subclass should override {@link getDefaultTagName}
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Brad Anderson <javalizard@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+class THtmlElement extends TWebControl
+{
+ /**
+ * @var the tag of this element
+ */
+ private $_tagName=null;
+
+ /**
+ * @return string the tag name of this control. Defaults to 'span'.
+ */
+ public function getTagName()
+ {
+ return ($this->_tagName !== null) ? $this->_tagName : ($this->_tagName = $this->getDefaultTagName());
+ }
+
+ /**
+ * @param string the tag name of this control.
+ */
+ public function setTagName($value)
+ {
+ $this->_tagName=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * This is the default tag when no other is specified
+ * @return string the default tag
+ */
+ public function getDefaultTagName() {
+ return 'span';
+ }
+
+ /**
+ * This tells you if this TagName has deviated from the original
+ * @return boolean true if TagName has deviated from the default.
+ */
+ public function getIsMutated() {
+ return $this->_tagName !== null && $this->_tagName != $this->getDefaultTagName();
+ }
+}
diff --git a/framework/Web/UI/WebControls/THyperLink.php b/framework/Web/UI/WebControls/THyperLink.php
index 1e32d6c9..b745f7b0 100644
--- a/framework/Web/UI/WebControls/THyperLink.php
+++ b/framework/Web/UI/WebControls/THyperLink.php
@@ -1,227 +1,227 @@
-<?php
-/**
- * THyperLink class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.xisc.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * THyperLink class
- *
- * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
- * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
- * the {@link setText Text} property. It is also possible to display an image
- * by setting the {@link setImageUrl ImageUrl} property. In this case,
- * {@link getText Text} is displayed as the alternate text of the image.
- * The link target is specified via the {@link setTarget Target} property.
- * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
- * the content enclosed within the control tag will be rendered.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLink extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name of the hyperlink
- */
- protected function getTagName()
- {
- return 'a';
- }
-
- /**
- * Adds attributes related to a hyperlink element to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $isEnabled=$this->getEnabled(true);
- if($this->getEnabled() && !$isEnabled)
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
- $writer->addAttribute('href',$url);
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
-
- /**
- * Renders the body content of the hyperlink.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if(($imageUrl=$this->getImageUrl())==='')
- {
- if(($text=$this->getText())!=='')
- $writer->write(THttpUtility::htmlEncode($text));
- else if($this->getHasControls())
- parent::renderContents($writer);
- else
- $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
- }
- else
- {
- $this->createImage($imageUrl)->renderControl($writer);
- }
- }
-
- /**
- * Gets the TImage for rendering the ImageUrl property. This is not for
- * creating dynamic images.
- * @param string image url.
- * @return TImage image control for rendering.
- */
- protected function createImage($imageUrl)
- {
- $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
- $image->setImageUrl($imageUrl);
- if(($width=$this->getImageWidth())!=='')
- $image->setWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $image->setHeight($height);
- if(($toolTip=$this->getToolTip())!=='')
- $image->setToolTip($toolTip);
- if(($text=$this->getText())!=='')
- $image->setAlternateText($text);
- $image->setBorderWidth('0');
- return $image;
- }
-
- /**
- * @return string the text caption of the THyperLink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the THyperLink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * Sets the height of the image in the THyperLink
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewSTate('ImageHeight',$value,'');
- }
-
- /**
- * @return string the location of the image file for the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * Sets the location of image file of the THyperLink.
- * @param string the image file location
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * Sets the width of the image in the THyperLink
- * @param string width of the image
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the THyperLink component is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * Returns the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text caption
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the URL to link to when the THyperLink component is clicked.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text caption to be set
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-}
-
+<?php
+/**
+ * THyperLink class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.xisc.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * THyperLink class
+ *
+ * THyperLink displays a hyperlink on a page. The hyperlink URL is specified
+ * via the {@link setNavigateUrl NavigateUrl} property, and link text is via
+ * the {@link setText Text} property. It is also possible to display an image
+ * by setting the {@link setImageUrl ImageUrl} property. In this case,
+ * {@link getText Text} is displayed as the alternate text of the image.
+ * The link target is specified via the {@link setTarget Target} property.
+ * If both {@link getImageUrl ImageUrl} and {@link getText Text} are empty,
+ * the content enclosed within the control tag will be rendered.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLink extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of the hyperlink
+ */
+ protected function getTagName()
+ {
+ return 'a';
+ }
+
+ /**
+ * Adds attributes related to a hyperlink element to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $isEnabled=$this->getEnabled(true);
+ if($this->getEnabled() && !$isEnabled)
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ if(($url=$this->getNavigateUrl())!=='' && $isEnabled)
+ $writer->addAttribute('href',$url);
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+
+ /**
+ * Renders the body content of the hyperlink.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if(($imageUrl=$this->getImageUrl())==='')
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write(THttpUtility::htmlEncode($text));
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ else
+ $writer->write(THttpUtility::htmlEncode($this->getNavigateUrl()));
+ }
+ else
+ {
+ $this->createImage($imageUrl)->renderControl($writer);
+ }
+ }
+
+ /**
+ * Gets the TImage for rendering the ImageUrl property. This is not for
+ * creating dynamic images.
+ * @param string image url.
+ * @return TImage image control for rendering.
+ */
+ protected function createImage($imageUrl)
+ {
+ $image=Prado::createComponent('System.Web.UI.WebControls.TImage');
+ $image->setImageUrl($imageUrl);
+ if(($width=$this->getImageWidth())!=='')
+ $image->setWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $image->setHeight($height);
+ if(($toolTip=$this->getToolTip())!=='')
+ $image->setToolTip($toolTip);
+ if(($text=$this->getText())!=='')
+ $image->setAlternateText($text);
+ $image->setBorderWidth('0');
+ return $image;
+ }
+
+ /**
+ * @return string the text caption of the THyperLink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the THyperLink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * Sets the height of the image in the THyperLink
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewSTate('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string the location of the image file for the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * Sets the location of image file of the THyperLink.
+ * @param string the image file location
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * Sets the width of the image in the THyperLink
+ * @param string width of the image
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the THyperLink component is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text caption
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the URL to link to when the THyperLink component is clicked.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text caption to be set
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the THyperLink component is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/THyperLinkColumn.php b/framework/Web/UI/WebControls/THyperLinkColumn.php
index a73880f1..faa4ce42 100644
--- a/framework/Web/UI/WebControls/THyperLinkColumn.php
+++ b/framework/Web/UI/WebControls/THyperLinkColumn.php
@@ -1,273 +1,273 @@
-<?php
-/**
- * THyperLinkColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-/**
- * THyperLink class file
- */
-Prado::using('System.Web.UI.WebControls.THyperLink');
-
-/**
- * THyperLinkColumn class
- *
- * THyperLinkColumn contains a hyperlink for each item in the column.
- * You can set the text and the url of the hyperlink by {@link setText Text}
- * and {@link setNavigateUrl NavigateUrl} properties, respectively.
- * You can also bind the text and url to specific data field in datasource
- * by setting {@link setDataTextField DataTextField} and
- * {@link setDataNavigateUrlField DataNavigateUrlField}.
- * Both can be formatted before rendering according to the
- * {@link setDataTextFormatString DataTextFormatString} and
- * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
- * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
- * are present, the latter takes precedence.
- * The same rule applies to {@link setNavigateUrl NavigateUrl} and
- * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
- *
- * The hyperlinks in the column can be accessed by one of the following two methods:
- * <code>
- * $datagridItem->HyperLinkColumnID->HyperLink
- * $datagridItem->HyperLinkColumnID->Controls[0]
- * </code>
- * The second method is possible because the hyperlink control created within the
- * datagrid cell is the first child.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THyperLinkColumn extends TDataGridColumn
-{
- /**
- * @return string the text caption of the hyperlink
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text caption of the hyperlink.
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the hyperlink caption
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the hyperlink caption
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the hyperlink caption will be displayed.
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string height of the image in the THyperLink
- */
- public function getImageHeight()
- {
- return $this->getViewState('ImageHeight','');
- }
-
- /**
- * @param string height of the image in the THyperLink
- */
- public function setImageHeight($value)
- {
- $this->setViewState('ImageHeight',$value,'');
- }
-
- /**
- * @return string url of the image in the THyperLink
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string url of the image in the THyperLink
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * @return string width of the image in the THyperLink
- */
- public function getImageWidth()
- {
- return $this->getViewState('ImageWidth','');
- }
-
- /**
- * @param string width of the image in the THyperLink
- */
- public function setImageWidth($value)
- {
- $this->setViewState('ImageWidth',$value,'');
- }
-
- /**
- * @return string the URL to link to when the hyperlink is clicked.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * Sets the URL to link to when the hyperlink is clicked.
- * @param string the URL
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',$value,'');
- }
-
- /**
- * @return string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function getDataNavigateUrlField()
- {
- return $this->getViewState('DataNavigateUrlField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the navigate url of hyperlink
- */
- public function setDataNavigateUrlField($value)
- {
- $this->setViewState('DataNavigateUrlField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function getDataNavigateUrlFormatString()
- {
- return $this->getViewState('DataNavigateUrlFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
- */
- public function setDataNavigateUrlFormatString($value)
- {
- $this->setViewState('DataNavigateUrlFormatString',$value,'');
- }
-
- /**
- * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
- * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',$value,'');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It creates a hyperlink within the cell.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- $link=new THyperLink;
- if(($url = $this->getImageUrl())!=='')
- {
- $link->setImageUrl($url);
- if(($width=$this->getImageWidth())!=='')
- $link->setImageWidth($width);
- if(($height=$this->getImageHeight())!=='')
- $link->setImageHeight($height);
- }
- $link->setText($this->getText());
- $link->setNavigateUrl($this->getNavigateUrl());
- $link->setTarget($this->getTarget());
- if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
- $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- $cell->getControls()->add($link);
- $cell->registerObject('HyperLink',$link);
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- if(($field=$this->getDataTextField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
- $sender->setText($text);
- }
- if(($field=$this->getDataNavigateUrlField())!=='')
- {
- $value=$this->getDataFieldValue($data,$field);
- $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
- $sender->setNavigateUrl($url);
- }
- }
-}
-
+<?php
+/**
+ * THyperLinkColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+/**
+ * THyperLink class file
+ */
+Prado::using('System.Web.UI.WebControls.THyperLink');
+
+/**
+ * THyperLinkColumn class
+ *
+ * THyperLinkColumn contains a hyperlink for each item in the column.
+ * You can set the text and the url of the hyperlink by {@link setText Text}
+ * and {@link setNavigateUrl NavigateUrl} properties, respectively.
+ * You can also bind the text and url to specific data field in datasource
+ * by setting {@link setDataTextField DataTextField} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField}.
+ * Both can be formatted before rendering according to the
+ * {@link setDataTextFormatString DataTextFormatString} and
+ * and {@link setDataNavigateUrlFormatString DataNavigateUrlFormatString}
+ * properties, respectively. If both {@link setText Text} and {@link setDataTextField DataTextField}
+ * are present, the latter takes precedence.
+ * The same rule applies to {@link setNavigateUrl NavigateUrl} and
+ * {@link setDataNavigateUrlField DataNavigateUrlField} properties.
+ *
+ * The hyperlinks in the column can be accessed by one of the following two methods:
+ * <code>
+ * $datagridItem->HyperLinkColumnID->HyperLink
+ * $datagridItem->HyperLinkColumnID->Controls[0]
+ * </code>
+ * The second method is possible because the hyperlink control created within the
+ * datagrid cell is the first child.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THyperLinkColumn extends TDataGridColumn
+{
+ /**
+ * @return string the text caption of the hyperlink
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text caption of the hyperlink.
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the hyperlink caption
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the hyperlink caption
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the hyperlink caption will be displayed.
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string height of the image in the THyperLink
+ */
+ public function getImageHeight()
+ {
+ return $this->getViewState('ImageHeight','');
+ }
+
+ /**
+ * @param string height of the image in the THyperLink
+ */
+ public function setImageHeight($value)
+ {
+ $this->setViewState('ImageHeight',$value,'');
+ }
+
+ /**
+ * @return string url of the image in the THyperLink
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string url of the image in the THyperLink
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * @return string width of the image in the THyperLink
+ */
+ public function getImageWidth()
+ {
+ return $this->getViewState('ImageWidth','');
+ }
+
+ /**
+ * @param string width of the image in the THyperLink
+ */
+ public function setImageWidth($value)
+ {
+ $this->setViewState('ImageWidth',$value,'');
+ }
+
+ /**
+ * @return string the URL to link to when the hyperlink is clicked.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * Sets the URL to link to when the hyperlink is clicked.
+ * @param string the URL
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',$value,'');
+ }
+
+ /**
+ * @return string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function getDataNavigateUrlField()
+ {
+ return $this->getViewState('DataNavigateUrlField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the navigate url of hyperlink
+ */
+ public function setDataNavigateUrlField($value)
+ {
+ $this->setViewState('DataNavigateUrlField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function getDataNavigateUrlFormatString()
+ {
+ return $this->getViewState('DataNavigateUrlFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the navigate url of hyperlink will be displayed.
+ */
+ public function setDataNavigateUrlFormatString($value)
+ {
+ $this->setViewState('DataNavigateUrlFormatString',$value,'');
+ }
+
+ /**
+ * @return string the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * Sets the target window or frame to display the Web page content linked to when the hyperlink is clicked.
+ * @param string the target window, valid values include '_blank', '_parent', '_self', '_top' and empty string.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',$value,'');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It creates a hyperlink within the cell.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ $link=new THyperLink;
+ if(($url = $this->getImageUrl())!=='')
+ {
+ $link->setImageUrl($url);
+ if(($width=$this->getImageWidth())!=='')
+ $link->setImageWidth($width);
+ if(($height=$this->getImageHeight())!=='')
+ $link->setImageHeight($height);
+ }
+ $link->setText($this->getText());
+ $link->setNavigateUrl($this->getNavigateUrl());
+ $link->setTarget($this->getTarget());
+ if($this->getDataTextField()!=='' || $this->getDataNavigateUrlField()!=='')
+ $link->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ $cell->getControls()->add($link);
+ $cell->registerObject('HyperLink',$link);
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ if(($field=$this->getDataTextField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $text=$this->formatDataValue($this->getDataTextFormatString(),$value);
+ $sender->setText($text);
+ }
+ if(($field=$this->getDataNavigateUrlField())!=='')
+ {
+ $value=$this->getDataFieldValue($data,$field);
+ $url=$this->formatDataValue($this->getDataNavigateUrlFormatString(),$value);
+ $sender->setNavigateUrl($url);
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TImage.php b/framework/Web/UI/WebControls/TImage.php
index 37f9a050..c8dde281 100644
--- a/framework/Web/UI/WebControls/TImage.php
+++ b/framework/Web/UI/WebControls/TImage.php
@@ -1,157 +1,157 @@
-<?php
-/**
- * TImage class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TImage class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TImage class
- *
- * TImage displays an image on a page. The image is specified via the
- * {@link setImageUrl ImageUrl} property which takes a relative or absolute
- * URL to the image file. The alignment of the image displayed is set by
- * the {@link setImageAlign ImageAlign} property. To set alternative texts
- * or long description of the image, use {@link setAlternateText AlternateText}
- * or {@link setDescriptionUrl DescriptionUrl} property, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImage extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name of image control
- */
- protected function getTagName()
- {
- return 'img';
- }
-
- /**
- * Adds attributes related to an HTML image element to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $writer->addAttribute('src',$this->getImageUrl());
- $writer->addAttribute('alt',$this->getAlternateText());
- if(($desc=$this->getDescriptionUrl())!=='')
- $writer->addAttribute('longdesc',$desc);
- if(($align=$this->getImageAlign())!=='')
- $writer->addAttribute('align',$align);
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the body content of the image.
- * Nothing to be rendered within image tags.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- }
-
- /**
- * @return string the alternative text displayed in the TImage component when the image is unavailable.
- */
- public function getAlternateText()
- {
- return $this->getViewState('AlternateText','');
- }
-
- /**
- * Sets the alternative text to be displayed in the TImage when the image is unavailable.
- * @param string the alternative text
- */
- public function setAlternateText($value)
- {
- $this->setViewState('AlternateText',$value,'');
- }
-
- /**
- * @return string the alignment of the image with respective to other elements on the page, defaults to empty.
- */
- public function getImageAlign()
- {
- return $this->getViewState('ImageAlign','');
- }
-
- /**
- * Sets the alignment of the image with respective to other elements on the page.
- * Possible values include: absbottom, absmiddle, baseline, bottom, left,
- * middle, right, texttop, and top. If an empty string is passed in,
- * imagealign attribute will not be rendered.
- * @param string the alignment of the image
- */
- public function setImageAlign($value)
- {
- $this->setViewState('ImageAlign',$value,'');
- }
-
- /**
- * @return string the URL of the image file
- */
- public function getImageUrl()
- {
- return $this->getViewState('ImageUrl','');
- }
-
- /**
- * @param string the URL of the image file
- */
- public function setImageUrl($value)
- {
- $this->setViewState('ImageUrl',$value,'');
- }
-
- /**
- * Returns the URL of the image file.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getImageUrl()}.
- * @return string the URL of the image file.
- * @see getImageUrl
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getImageUrl();
- }
-
- /**
- * Sets the URL of the image.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setImageUrl()}.
- * @param string the URL of the image file.
- * @see setImageUrl
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setImageUrl($value);
- }
-
- /**
- * @return string the URL to long description
- */
- public function getDescriptionUrl()
- {
- return $this->getViewState('DescriptionUrl','');
- }
-
- /**
- * @param string the URL to the long description of the image.
- */
- public function setDescriptionUrl($value)
- {
- $this->setViewState('DescriptionUrl',$value,'');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TImage class
+ *
+ * TImage displays an image on a page. The image is specified via the
+ * {@link setImageUrl ImageUrl} property which takes a relative or absolute
+ * URL to the image file. The alignment of the image displayed is set by
+ * the {@link setImageAlign ImageAlign} property. To set alternative texts
+ * or long description of the image, use {@link setAlternateText AlternateText}
+ * or {@link setDescriptionUrl DescriptionUrl} property, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImage extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name of image control
+ */
+ protected function getTagName()
+ {
+ return 'img';
+ }
+
+ /**
+ * Adds attributes related to an HTML image element to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $writer->addAttribute('src',$this->getImageUrl());
+ $writer->addAttribute('alt',$this->getAlternateText());
+ if(($desc=$this->getDescriptionUrl())!=='')
+ $writer->addAttribute('longdesc',$desc);
+ if(($align=$this->getImageAlign())!=='')
+ $writer->addAttribute('align',$align);
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the body content of the image.
+ * Nothing to be rendered within image tags.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ }
+
+ /**
+ * @return string the alternative text displayed in the TImage component when the image is unavailable.
+ */
+ public function getAlternateText()
+ {
+ return $this->getViewState('AlternateText','');
+ }
+
+ /**
+ * Sets the alternative text to be displayed in the TImage when the image is unavailable.
+ * @param string the alternative text
+ */
+ public function setAlternateText($value)
+ {
+ $this->setViewState('AlternateText',$value,'');
+ }
+
+ /**
+ * @return string the alignment of the image with respective to other elements on the page, defaults to empty.
+ */
+ public function getImageAlign()
+ {
+ return $this->getViewState('ImageAlign','');
+ }
+
+ /**
+ * Sets the alignment of the image with respective to other elements on the page.
+ * Possible values include: absbottom, absmiddle, baseline, bottom, left,
+ * middle, right, texttop, and top. If an empty string is passed in,
+ * imagealign attribute will not be rendered.
+ * @param string the alignment of the image
+ */
+ public function setImageAlign($value)
+ {
+ $this->setViewState('ImageAlign',$value,'');
+ }
+
+ /**
+ * @return string the URL of the image file
+ */
+ public function getImageUrl()
+ {
+ return $this->getViewState('ImageUrl','');
+ }
+
+ /**
+ * @param string the URL of the image file
+ */
+ public function setImageUrl($value)
+ {
+ $this->setViewState('ImageUrl',$value,'');
+ }
+
+ /**
+ * Returns the URL of the image file.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getImageUrl()}.
+ * @return string the URL of the image file.
+ * @see getImageUrl
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getImageUrl();
+ }
+
+ /**
+ * Sets the URL of the image.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setImageUrl()}.
+ * @param string the URL of the image file.
+ * @see setImageUrl
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setImageUrl($value);
+ }
+
+ /**
+ * @return string the URL to long description
+ */
+ public function getDescriptionUrl()
+ {
+ return $this->getViewState('DescriptionUrl','');
+ }
+
+ /**
+ * @param string the URL to the long description of the image.
+ */
+ public function setDescriptionUrl($value)
+ {
+ $this->setViewState('DescriptionUrl',$value,'');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TImageButton.php b/framework/Web/UI/WebControls/TImageButton.php
index 350c84d4..a92a9df8 100644
--- a/framework/Web/UI/WebControls/TImageButton.php
+++ b/framework/Web/UI/WebControls/TImageButton.php
@@ -1,442 +1,442 @@
-<?php
-/**
- * TImageButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TImageButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TImage class file
- */
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TImageButton class
- *
- * TImageButton creates an image button on the page. It is used to submit data to a page.
- * You can create either a <b>submit</b> button or a <b>command</b> button.
- *
- * A <b>command</b> button has a command name (specified by
- * the {@link setCommandName CommandName} property) and and a command parameter
- * (specified by {@link setCommandParameter CommandParameter} property)
- * associated with the button. This allows you to create multiple TLinkButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter. You can provide an event handler for
- * {@link onCommand OnCommand} event to programmatically control the actions performed
- * when the command button is clicked. In the event handler, you can determine
- * the {@link setCommandName CommandName} property value and
- * the {@link setCommandParameter CommandParameter} property value
- * through the {@link TCommandParameter::getName Name} and
- * {@link TCommandParameter::getParameter Parameter} properties of the event
- * parameter which is of type {@link TCommandEventParameter}.
- *
- * A <b>submit</b> button does not have a command name associated with the button
- * and clicking on it simply posts the Web page back to the server.
- * By default, a TImageButton control is a submit button.
- * You can provide an event handler for the {@link onClick OnClick} event
- * to programmatically control the actions performed when the submit button is clicked.
- * The coordinates of the clicking point can be obtained from the {@link onClick OnClick}
- * event parameter, which is of type {@link TImageClickEventParameter}.
- *
- * Clicking on button can trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * And the validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TImageButton displays the {@link setText Text} property as the hint text to the displayed image.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageButton extends TImage implements IPostBackDataHandler, IPostBackEventHandler, IButtonControl
-{
- /**
- * @var integer x coordinate that the image is being clicked at
- */
- private $_x=0;
- /**
- * @var integer y coordinate that the image is being clicked at
- */
- private $_y=0;
- private $_dataChanged=false;
-
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- $writer->addAttribute('type','image');
- if(($uniqueID=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uniqueID);
- if($this->getEnabled(true))
- {
- if($this->getEnableClientScript() && $this->needPostBackScript())
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TImageButton';
- }
-
- /**
- * @return boolean whether to perform validation if the button is clicked
- */
- protected function canCauseValidation()
- {
- if($this->getCausesValidation())
- {
- $group=$this->getValidationGroup();
- return $this->getPage()->getValidators($group)->getCount()>0;
- }
- else
- return false;
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * @return boolean whether the button needs javascript to do postback
- */
- protected function needPostBackScript()
- {
- return $this->canCauseValidation() || $this->getIsDefaultButton();
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['EventTarget'] = $this->getUniqueID();
-
- return $options;
- }
-
- /**
- * This method checks if the TImageButton is clicked and loads the coordinates of the clicking position.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $uid=$this->getUniqueID();
- if(isset($values["{$uid}_x"]) && isset($values["{$uid}_y"]))
- {
- $this->_x=intval($values["{$uid}_x"]);
- $this->_y=intval($values["{$uid}_y"]);
- if($this->getPage()->getPostBackEventTarget()===null)
- $this->getPage()->setPostBackEventTarget($this);
- $this->_dataChanged=true;
- }
- return false;
- }
-
- /**
- * A dummy implementation for the IPostBackDataHandler interface.
- */
- public function raisePostDataChangedEvent()
- {
- // no post data to handle
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TImageClickEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(new TImageClickEventParameter($this->_x,$this->_y));
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this button will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string caption of the button
- */
- public function getText()
- {
- return $this->getAlternateText();
- }
-
- /**
- * @param string caption of the button
- */
- public function setText($value)
- {
- $this->setAlternateText($value);
- }
-
- /**
- * Registers the image button to receive postback data during postback.
- * This is necessary because an image button, when postback, does not have
- * direct mapping between post data and the image button name.
- * This method overrides the parent implementation and is invoked before render.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * This overrides the parent implementation with nothing to be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- }
-}
-
-/**
- * TImageClickEventParameter class
- *
- * TImageClickEventParameter encapsulates the parameter data for
- * {@link TImageButton::onClick Click} event of {@link TImageButton} controls.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageClickEventParameter extends TEventParameter
-{
- /**
- * the X coordinate of the clicking point
- * @var integer
- */
- private $_x=0;
- /**
- * the Y coordinate of the clicking point
- * @var integer
- */
- private $_y=0;
-
- /**
- * Constructor.
- * @param integer X coordinate of the clicking point
- * @param integer Y coordinate of the clicking point
- */
- public function __construct($x,$y)
- {
- $this->_x=$x;
- $this->_y=$y;
- }
-
- /**
- * @return integer X coordinate of the clicking point, defaults to 0
- */
- public function getX()
- {
- return $this->_x;
- }
-
- /**
- * @param integer X coordinate of the clicking point
- */
- public function setX($value)
- {
- $this->_x=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return integer Y coordinate of the clicking point, defaults to 0
- */
- public function getY()
- {
- return $this->_y;
- }
-
- /**
- * @param integer Y coordinate of the clicking point
- */
- public function setY($value)
- {
- $this->_y=TPropertyValue::ensureInteger($value);
- }
-}
-
-?>
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TImage class file
+ */
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TImageButton class
+ *
+ * TImageButton creates an image button on the page. It is used to submit data to a page.
+ * You can create either a <b>submit</b> button or a <b>command</b> button.
+ *
+ * A <b>command</b> button has a command name (specified by
+ * the {@link setCommandName CommandName} property) and and a command parameter
+ * (specified by {@link setCommandParameter CommandParameter} property)
+ * associated with the button. This allows you to create multiple TLinkButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter. You can provide an event handler for
+ * {@link onCommand OnCommand} event to programmatically control the actions performed
+ * when the command button is clicked. In the event handler, you can determine
+ * the {@link setCommandName CommandName} property value and
+ * the {@link setCommandParameter CommandParameter} property value
+ * through the {@link TCommandParameter::getName Name} and
+ * {@link TCommandParameter::getParameter Parameter} properties of the event
+ * parameter which is of type {@link TCommandEventParameter}.
+ *
+ * A <b>submit</b> button does not have a command name associated with the button
+ * and clicking on it simply posts the Web page back to the server.
+ * By default, a TImageButton control is a submit button.
+ * You can provide an event handler for the {@link onClick OnClick} event
+ * to programmatically control the actions performed when the submit button is clicked.
+ * The coordinates of the clicking point can be obtained from the {@link onClick OnClick}
+ * event parameter, which is of type {@link TImageClickEventParameter}.
+ *
+ * Clicking on button can trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * And the validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TImageButton displays the {@link setText Text} property as the hint text to the displayed image.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageButton extends TImage implements IPostBackDataHandler, IPostBackEventHandler, IButtonControl
+{
+ /**
+ * @var integer x coordinate that the image is being clicked at
+ */
+ private $_x=0;
+ /**
+ * @var integer y coordinate that the image is being clicked at
+ */
+ private $_y=0;
+ private $_dataChanged=false;
+
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'input';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ $writer->addAttribute('type','image');
+ if(($uniqueID=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uniqueID);
+ if($this->getEnabled(true))
+ {
+ if($this->getEnableClientScript() && $this->needPostBackScript())
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TImageButton';
+ }
+
+ /**
+ * @return boolean whether to perform validation if the button is clicked
+ */
+ protected function canCauseValidation()
+ {
+ if($this->getCausesValidation())
+ {
+ $group=$this->getValidationGroup();
+ return $this->getPage()->getValidators($group)->getCount()>0;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * @return boolean whether the button needs javascript to do postback
+ */
+ protected function needPostBackScript()
+ {
+ return $this->canCauseValidation() || $this->getIsDefaultButton();
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['EventTarget'] = $this->getUniqueID();
+
+ return $options;
+ }
+
+ /**
+ * This method checks if the TImageButton is clicked and loads the coordinates of the clicking position.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $uid=$this->getUniqueID();
+ if(isset($values["{$uid}_x"]) && isset($values["{$uid}_y"]))
+ {
+ $this->_x=intval($values["{$uid}_x"]);
+ $this->_y=intval($values["{$uid}_y"]);
+ if($this->getPage()->getPostBackEventTarget()===null)
+ $this->getPage()->setPostBackEventTarget($this);
+ $this->_dataChanged=true;
+ }
+ return false;
+ }
+
+ /**
+ * A dummy implementation for the IPostBackDataHandler interface.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ // no post data to handle
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TImageClickEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(new TImageClickEventParameter($this->_x,$this->_y));
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this button will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string caption of the button
+ */
+ public function getText()
+ {
+ return $this->getAlternateText();
+ }
+
+ /**
+ * @param string caption of the button
+ */
+ public function setText($value)
+ {
+ $this->setAlternateText($value);
+ }
+
+ /**
+ * Registers the image button to receive postback data during postback.
+ * This is necessary because an image button, when postback, does not have
+ * direct mapping between post data and the image button name.
+ * This method overrides the parent implementation and is invoked before render.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * This overrides the parent implementation with nothing to be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ }
+}
+
+/**
+ * TImageClickEventParameter class
+ *
+ * TImageClickEventParameter encapsulates the parameter data for
+ * {@link TImageButton::onClick Click} event of {@link TImageButton} controls.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageClickEventParameter extends TEventParameter
+{
+ /**
+ * the X coordinate of the clicking point
+ * @var integer
+ */
+ private $_x=0;
+ /**
+ * the Y coordinate of the clicking point
+ * @var integer
+ */
+ private $_y=0;
+
+ /**
+ * Constructor.
+ * @param integer X coordinate of the clicking point
+ * @param integer Y coordinate of the clicking point
+ */
+ public function __construct($x,$y)
+ {
+ $this->_x=$x;
+ $this->_y=$y;
+ }
+
+ /**
+ * @return integer X coordinate of the clicking point, defaults to 0
+ */
+ public function getX()
+ {
+ return $this->_x;
+ }
+
+ /**
+ * @param integer X coordinate of the clicking point
+ */
+ public function setX($value)
+ {
+ $this->_x=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return integer Y coordinate of the clicking point, defaults to 0
+ */
+ public function getY()
+ {
+ return $this->_y;
+ }
+
+ /**
+ * @param integer Y coordinate of the clicking point
+ */
+ public function setY($value)
+ {
+ $this->_y=TPropertyValue::ensureInteger($value);
+ }
+}
+
+?>
diff --git a/framework/Web/UI/WebControls/TImageMap.php b/framework/Web/UI/WebControls/TImageMap.php
index 5907d03d..718a3414 100644
--- a/framework/Web/UI/WebControls/TImageMap.php
+++ b/framework/Web/UI/WebControls/TImageMap.php
@@ -1,837 +1,837 @@
-<?php
-/**
- * TImageMap and related class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TImageMap and related class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TImage class file
- */
-Prado::using('System.Web.UI.WebControls.TImage');
-
-/**
- * TImageMap class
- *
- * TImageMap represents an image on a page. Hotspot regions can be defined
- * within the image. Depending on the {@link setHotSpotMode HotSpotMode},
- * clicking on the hotspots may trigger a postback or navigate to a specified
- * URL. The hotspots defined may be accessed via {@link getHotSpots HotSpots}.
- * Each hotspot is described as a {@link THotSpot}, which can be a circle,
- * rectangle, polygon, etc. To add hotspot in a template, use the following,
- * <code>
- * <com:TImageMap>
- * <com:TCircleHotSpot ... />
- * <com:TRectangleHotSpot ... />
- * <com:TPolygonHotSpot ... />
- * </com:TImageMap>
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageMap extends TImage implements IPostBackEventHandler
-{
- const MAP_NAME_PREFIX='ImageMap';
-
- /**
- * Processes an object that is created during parsing template.
- * This method adds {@link THotSpot} objects into the hotspot collection
- * of the imagemap.
- * @param string|TComponent text string or component parsed and instantiated in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof THotSpot)
- $this->getHotSpots()->add($object);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional imagemap specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if($this->getHotSpots()->getCount()>0)
- {
- $writer->addAttribute('usemap','#'.self::MAP_NAME_PREFIX.$this->getClientID());
- $writer->addAttribute('id',$this->getUniqueID());
- }
- if($this->getEnabled() && !$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Renders this imagemap.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- parent::render($writer);
-
- $hotspots=$this->getHotSpots();
-
- if($hotspots->getCount()>0)
- {
- $clientID=$this->getClientID();
- $cs=$this->getPage()->getClientScript();
- $writer->writeLine();
- $writer->addAttribute('name',self::MAP_NAME_PREFIX.$clientID);
- $writer->renderBeginTag('map');
- $writer->writeLine();
- if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=THotSpotMode::Navigate;
- $target=$this->getTarget();
- $i=0;
- $options['EventTarget'] = $this->getUniqueID();
- $options['StopEvent'] = true;
- $cs=$this->getPage()->getClientScript();
- foreach($hotspots as $hotspot)
- {
- if($hotspot->getHotSpotMode()===THotSpotMode::NotSet)
- $hotspot->setHotSpotMode($mode);
- if($target!=='' && $hotspot->getTarget()==='')
- $hotspot->setTarget($target);
- if($hotspot->getHotSpotMode()===THotSpotMode::PostBack)
- {
- $id=$clientID.'_'.$i;
- $writer->addAttribute('id',$id);
- $writer->addAttribute('href','#'.$id); //create unique no-op url references
- $options['ID']=$id;
- $options['EventParameter']="$i";
- $options['CausesValidation']=$hotspot->getCausesValidation();
- $options['ValidationGroup']=$hotspot->getValidationGroup();
- $cs->registerPostBackControl($this->getClientClassName(),$options);
- }
- $hotspot->render($writer);
- $writer->writeLine();
- $i++;
- }
- $writer->renderEndTag();
- }
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TImageMap';
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- $postBackValue=null;
- if($param!=='')
- {
- $index=TPropertyValue::ensureInteger($param);
- $hotspots=$this->getHotSpots();
- if($index>=0 && $index<$hotspots->getCount())
- {
- $hotspot=$hotspots->itemAt($index);
- if(($mode=$hotspot->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=$this->getHotSpotMode();
- if($mode===THotSpotMode::PostBack)
- {
- $postBackValue=$hotspot->getPostBackValue();
- if($hotspot->getCausesValidation())
- $this->getPage()->validate($hotspot->getValidationGroup());
- }
- }
- }
- if($postBackValue!==null)
- $this->onClick(new TImageMapEventParameter($postBackValue));
- }
-
- /**
- * @return THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. Defaults to THotSpotMode::NotSet.
- */
- public function getHotSpotMode()
- {
- return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
- }
-
- /**
- * Sets the behavior of hotspot regions in this imagemap when they are clicked.
- * If an individual hotspot has a mode other than 'NotSet', the mode set in this
- * imagemap will be ignored. By default, 'NotSet' is equivalent to 'Navigate'.
- * @param THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked.
- */
- public function setHotSpotMode($value)
- {
- $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
- }
-
- /**
- * @return THotSpotCollection collection of hotspots defined in this imagemap.
- */
- public function getHotSpots()
- {
- if(($hotspots=$this->getViewState('HotSpots',null))===null)
- {
- $hotspots=new THotSpotCollection;
- $this->setViewState('HotSpots',$hotspots);
- }
- return $hotspots;
- }
-
- /**
- * @return string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. Defaults to ''.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the new page when a hotspot region is clicked within the imagemap.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * Raises <b>OnClick</b> event.
- * This method is invoked when a hotspot region is clicked within the imagemap.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TImageMapEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-}
-
-/**
- * TImageMapEventParameter class.
- *
- * TImageMapEventParameter represents a postback event parameter
- * when a hotspot is clicked and posts back in a {@link TImageMap}.
- * To retrieve the post back value associated with the hotspot being clicked,
- * access {@link getPostBackValue PostBackValue}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TImageMapEventParameter extends TEventParameter
-{
- private $_postBackValue;
-
- /**
- * Constructor.
- * @param string post back value associated with the hotspot clicked
- */
- public function __construct($postBackValue)
- {
- $this->_postBackValue=$postBackValue;
- }
-
- /**
- * @return string post back value associated with the hotspot clicked
- */
- public function getPostBackValue()
- {
- return $this->_postBackValue;
- }
-}
-
-/**
- * THotSpotCollection class.
- *
- * THotSpotCollection represents a collection of hotspots in an imagemap.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class THotSpotCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only {@link THotSpot}.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a THotSpot.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof THotSpot)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('hotspotcollection_hotspot_required');
- }
-}
-
-
-/**
- * THotSpot class.
- *
- * THotSpot implements the basic functionality common to all hot spot shapes.
- * Derived classes include {@link TCircleHotSpot}, {@link TPolygonHotSpot}
- * and {@link TRectangleHotSpot}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class THotSpot extends TComponent
-{
- private $_viewState=array();
-
- /**
- * Returns a viewstate value.
- *
- * This function is very useful in defining getter functions for component properties
- * that must be kept in viewstate.
- * @param string the name of the viewstate value to be returned
- * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
- * @return mixed the viewstate value corresponding to $key
- */
- protected function getViewState($key,$defaultValue=null)
- {
- return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
- }
-
- /**
- * Sets a viewstate value.
- *
- * This function is very useful in defining setter functions for control properties
- * that must be kept in viewstate.
- * Make sure that the viewstate value must be serializable and unserializable.
- * @param string the name of the viewstate value
- * @param mixed the viewstate value to be set
- * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
- */
- protected function setViewState($key,$value,$defaultValue=null)
- {
- if($value===$defaultValue)
- unset($this->_viewState[$key]);
- else
- $this->_viewState[$key]=$value;
- }
-
- /**
- * @return string shape of the hotspot, can be 'circle', 'rect', 'poly', etc.
- */
- abstract public function getShape();
- /**
- * @return string coordinates defining the hotspot shape.
- */
- abstract public function getCoordinates();
-
- /**
- * @return string the access key that allows you to quickly navigate to the HotSpot region. Defaults to ''.
- */
- public function getAccessKey()
- {
- return $this->getViewState('AccessKey','');
- }
-
- /**
- * @param string the access key that allows you to quickly navigate to the HotSpot region.
- */
- public function setAccessKey($value)
- {
- $this->setViewState('AccessKey',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the alternate text to display for a HotSpot object. Defaults to ''.
- */
- public function getAlternateText()
- {
- return $this->getViewState('AlternateText','');
- }
-
- /**
- * @param string the alternate text to display for a HotSpot object.
- */
- public function setAlternateText($value)
- {
- $this->setViewState('AlternateText',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return THotSpotMode the behavior of a HotSpot object when it is clicked. Defaults to THotSpotMode::NotSet.
- */
- public function getHotSpotMode()
- {
- return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
- }
-
- /**
- * @param THotSpotMode the behavior of a HotSpot object when it is clicked.
- */
- public function setHotSpotMode($value)
- {
- $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
- }
-
- /**
- * @return string the URL to navigate to when a HotSpot object is clicked. Defaults to ''.
- */
- public function getNavigateUrl()
- {
- return $this->getViewState('NavigateUrl','');
- }
-
- /**
- * @param string the URL to navigate to when a HotSpot object is clicked.
- */
- public function setNavigateUrl($value)
- {
- $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string a value that is post back when the HotSpot is clicked. Defaults to ''.
- */
- public function getPostBackValue()
- {
- return $this->getViewState('PostBackValue','');
- }
-
- /**
- * @param string a value that is post back when the HotSpot is clicked.
- */
- public function setPostBackValue($value)
- {
- $this->setViewState('PostBackValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return integer the tab index of the HotSpot region. Defaults to 0.
- */
- public function getTabIndex()
- {
- return $this->getViewState('TabIndex',0);
- }
-
- /**
- * @param integer the tab index of the HotSpot region.
- */
- public function setTabIndex($value)
- {
- $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return boolean whether postback event trigger by this hotspot will cause input validation, default is true
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this hotspot will cause input validation
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the hotspot causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the hotspot causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the target window or frame to display the new page when the HotSpot region
- * is clicked. Defaults to ''.
- */
- public function getTarget()
- {
- return $this->getViewState('Target','');
- }
-
- /**
- * @param string the target window or frame to display the new page when the HotSpot region
- * is clicked.
- */
- public function setTarget($value)
- {
- $this->setViewState('Target',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return boolean whether the hotspot has custom attributes
- */
- public function getHasAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->getCount()>0;
- else
- return false;
- }
-
- /**
- * Returns the list of custom attributes.
- * Custom attributes are name-value pairs that may be rendered
- * as HTML tags' attributes.
- * @return TAttributeCollection the list of custom attributes
- */
- public function getAttributes()
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes;
- else
- {
- $attributes=new TAttributeCollection;
- $this->setViewState('Attributes',$attributes,null);
- return $attributes;
- }
- }
-
- /**
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->contains($name);
- else
- return false;
- }
-
- /**
- * @return string attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->itemAt($name);
- else
- return null;
- }
-
- /**
- * Sets a custom hotspot attribute.
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, null if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- if($attributes=$this->getViewState('Attributes',null))
- return $attributes->remove($name);
- else
- return null;
- }
-
- /**
- * Renders this hotspot.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- $writer->addAttribute('shape',$this->getShape());
- $writer->addAttribute('coords',$this->getCoordinates());
- if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
- $mode=THotSpotMode::Navigate;
- if($mode===THotSpotMode::Navigate)
- {
- $writer->addAttribute('href',$this->getNavigateUrl());
- if(($target=$this->getTarget())!=='')
- $writer->addAttribute('target',$target);
- }
- else if($mode===THotSpotMode::Inactive)
- $writer->addAttribute('nohref','true');
- $text=$this->getAlternateText();
- $writer->addAttribute('title',$text);
- $writer->addAttribute('alt',$text);
- if(($accessKey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accessKey);
- if(($tabIndex=$this->getTabIndex())!==0)
- $writer->addAttribute('tabindex',"$tabIndex");
- if($this->getHasAttributes())
- {
- foreach($this->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
- $writer->renderBeginTag('area');
- $writer->renderEndTag();
- }
-}
-
-/**
- * Class TCircleHotSpot.
- *
- * TCircleHotSpot defines a circular hot spot region in a {@link TImageMap}
- * control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCircleHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'circle';
- }
-
- /**
- * @return string coordinates defining this hotspot shape
- */
- public function getCoordinates()
- {
- return $this->getX().','.$this->getY().','.$this->getRadius();
- }
-
- /**
- * @return integer radius of the circular HotSpot region. Defaults to 0.
- */
- public function getRadius()
- {
- return $this->getViewState('Radius',0);
- }
-
- /**
- * @param integer radius of the circular HotSpot region.
- */
- public function setRadius($value)
- {
- $this->setViewState('Radius',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the center of the circular HotSpot region. Defaults to 0.
- */
- public function getX()
- {
- return $this->getViewState('X',0);
- }
-
- /**
- * @param integer the X coordinate of the center of the circular HotSpot region.
- */
- public function setX($value)
- {
- $this->setViewState('X',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the Y coordinate of the center of the circular HotSpot region. Defaults to 0.
- */
- public function getY()
- {
- return $this->getViewState('Y',0);
- }
-
- /**
- * @param integer the Y coordinate of the center of the circular HotSpot region.
- */
- public function setY($value)
- {
- $this->setViewState('Y',TPropertyValue::ensureInteger($value),0);
- }
-}
-
-/**
- * Class TRectangleHotSpot.
- *
- * TRectangleHotSpot defines a rectangle hot spot region in a {@link
- * TImageMap} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRectangleHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'rect';
- }
-
- /**
- * @return string coordinates defining this hotspot shape
- */
- public function getCoordinates()
- {
- return $this->getLeft().','.$this->getTop().','.$this->getRight().','.$this->getBottom();
- }
-
- /**
- * @return integer the Y coordinate of the bottom side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getBottom()
- {
- return $this->getViewState('Bottom',0);
- }
-
- /**
- * @param integer the Y coordinate of the bottom side of the rectangle HotSpot region.
- */
- public function setBottom($value)
- {
- $this->setViewState('Bottom',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getLeft()
- {
- return $this->getViewState('Left',0);
- }
-
- /**
- * @param integer the X coordinate of the right side of the rectangle HotSpot region.
- */
- public function setLeft($value)
- {
- $this->setViewState('Left',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getRight()
- {
- return $this->getViewState('Right',0);
- }
-
- /**
- * @param integer the X coordinate of the right side of the rectangle HotSpot region.
- */
- public function setRight($value)
- {
- $this->setViewState('Right',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the Y coordinate of the top side of the rectangle HotSpot region. Defaults to 0.
- */
- public function getTop()
- {
- return $this->getViewState('Top',0);
- }
-
- /**
- * @param integer the Y coordinate of the top side of the rectangle HotSpot region.
- */
- public function setTop($value)
- {
- $this->setViewState('Top',TPropertyValue::ensureInteger($value),0);
- }
-}
-
-/**
- * Class TPolygonHotSpot.
- *
- * TPolygonHotSpot defines a polygon hot spot region in a {@link
- * TImageMap} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPolygonHotSpot extends THotSpot
-{
- /**
- * @return string shape of this hotspot.
- */
- public function getShape()
- {
- return 'poly';
- }
-
- /**
- * @return string coordinates of the vertices defining the polygon.
- * Coordinates are concatenated together with comma ','. Each pair
- * represents (x,y) of a vertex.
- */
- public function getCoordinates()
- {
- return $this->getViewState('Coordinates','');
- }
-
- /**
- * @param string coordinates of the vertices defining the polygon.
- * Coordinates are concatenated together with comma ','. Each pair
- * represents (x,y) of a vertex.
- */
- public function setCoordinates($value)
- {
- $this->setViewState('Coordinates',$value,'');
- }
-}
-
-
-/**
- * THotSpotMode class.
- * THotSpotMode defines the enumerable type for the possible hot spot modes.
- *
- * The following enumerable values are defined:
- * - NotSet: the mode is not specified
- * - Navigate: clicking on the hotspot will redirect the browser to a different page
- * - PostBack: clicking on the hotspot will cause a postback
- * - Inactive: the hotspot is inactive (not clickable)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class THotSpotMode extends TEnumerable
-{
- const NotSet='NotSet';
- const Navigate='Navigate';
- const PostBack='PostBack';
- const Inactive='Inactive';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TImage class file
+ */
+Prado::using('System.Web.UI.WebControls.TImage');
+
+/**
+ * TImageMap class
+ *
+ * TImageMap represents an image on a page. Hotspot regions can be defined
+ * within the image. Depending on the {@link setHotSpotMode HotSpotMode},
+ * clicking on the hotspots may trigger a postback or navigate to a specified
+ * URL. The hotspots defined may be accessed via {@link getHotSpots HotSpots}.
+ * Each hotspot is described as a {@link THotSpot}, which can be a circle,
+ * rectangle, polygon, etc. To add hotspot in a template, use the following,
+ * <code>
+ * <com:TImageMap>
+ * <com:TCircleHotSpot ... />
+ * <com:TRectangleHotSpot ... />
+ * <com:TPolygonHotSpot ... />
+ * </com:TImageMap>
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageMap extends TImage implements IPostBackEventHandler
+{
+ const MAP_NAME_PREFIX='ImageMap';
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method adds {@link THotSpot} objects into the hotspot collection
+ * of the imagemap.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof THotSpot)
+ $this->getHotSpots()->add($object);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional imagemap specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if($this->getHotSpots()->getCount()>0)
+ {
+ $writer->addAttribute('usemap','#'.self::MAP_NAME_PREFIX.$this->getClientID());
+ $writer->addAttribute('id',$this->getUniqueID());
+ }
+ if($this->getEnabled() && !$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Renders this imagemap.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ parent::render($writer);
+
+ $hotspots=$this->getHotSpots();
+
+ if($hotspots->getCount()>0)
+ {
+ $clientID=$this->getClientID();
+ $cs=$this->getPage()->getClientScript();
+ $writer->writeLine();
+ $writer->addAttribute('name',self::MAP_NAME_PREFIX.$clientID);
+ $writer->renderBeginTag('map');
+ $writer->writeLine();
+ if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=THotSpotMode::Navigate;
+ $target=$this->getTarget();
+ $i=0;
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['StopEvent'] = true;
+ $cs=$this->getPage()->getClientScript();
+ foreach($hotspots as $hotspot)
+ {
+ if($hotspot->getHotSpotMode()===THotSpotMode::NotSet)
+ $hotspot->setHotSpotMode($mode);
+ if($target!=='' && $hotspot->getTarget()==='')
+ $hotspot->setTarget($target);
+ if($hotspot->getHotSpotMode()===THotSpotMode::PostBack)
+ {
+ $id=$clientID.'_'.$i;
+ $writer->addAttribute('id',$id);
+ $writer->addAttribute('href','#'.$id); //create unique no-op url references
+ $options['ID']=$id;
+ $options['EventParameter']="$i";
+ $options['CausesValidation']=$hotspot->getCausesValidation();
+ $options['ValidationGroup']=$hotspot->getValidationGroup();
+ $cs->registerPostBackControl($this->getClientClassName(),$options);
+ }
+ $hotspot->render($writer);
+ $writer->writeLine();
+ $i++;
+ }
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TImageMap';
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ $postBackValue=null;
+ if($param!=='')
+ {
+ $index=TPropertyValue::ensureInteger($param);
+ $hotspots=$this->getHotSpots();
+ if($index>=0 && $index<$hotspots->getCount())
+ {
+ $hotspot=$hotspots->itemAt($index);
+ if(($mode=$hotspot->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=$this->getHotSpotMode();
+ if($mode===THotSpotMode::PostBack)
+ {
+ $postBackValue=$hotspot->getPostBackValue();
+ if($hotspot->getCausesValidation())
+ $this->getPage()->validate($hotspot->getValidationGroup());
+ }
+ }
+ }
+ if($postBackValue!==null)
+ $this->onClick(new TImageMapEventParameter($postBackValue));
+ }
+
+ /**
+ * @return THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked. Defaults to THotSpotMode::NotSet.
+ */
+ public function getHotSpotMode()
+ {
+ return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
+ }
+
+ /**
+ * Sets the behavior of hotspot regions in this imagemap when they are clicked.
+ * If an individual hotspot has a mode other than 'NotSet', the mode set in this
+ * imagemap will be ignored. By default, 'NotSet' is equivalent to 'Navigate'.
+ * @param THotSpotMode the behavior of hotspot regions in this imagemap when they are clicked.
+ */
+ public function setHotSpotMode($value)
+ {
+ $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
+ }
+
+ /**
+ * @return THotSpotCollection collection of hotspots defined in this imagemap.
+ */
+ public function getHotSpots()
+ {
+ if(($hotspots=$this->getViewState('HotSpots',null))===null)
+ {
+ $hotspots=new THotSpotCollection;
+ $this->setViewState('HotSpots',$hotspots);
+ }
+ return $hotspots;
+ }
+
+ /**
+ * @return string the target window or frame to display the new page when a hotspot region is clicked within the imagemap. Defaults to ''.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the new page when a hotspot region is clicked within the imagemap.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * Raises <b>OnClick</b> event.
+ * This method is invoked when a hotspot region is clicked within the imagemap.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TImageMapEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+}
+
+/**
+ * TImageMapEventParameter class.
+ *
+ * TImageMapEventParameter represents a postback event parameter
+ * when a hotspot is clicked and posts back in a {@link TImageMap}.
+ * To retrieve the post back value associated with the hotspot being clicked,
+ * access {@link getPostBackValue PostBackValue}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TImageMapEventParameter extends TEventParameter
+{
+ private $_postBackValue;
+
+ /**
+ * Constructor.
+ * @param string post back value associated with the hotspot clicked
+ */
+ public function __construct($postBackValue)
+ {
+ $this->_postBackValue=$postBackValue;
+ }
+
+ /**
+ * @return string post back value associated with the hotspot clicked
+ */
+ public function getPostBackValue()
+ {
+ return $this->_postBackValue;
+ }
+}
+
+/**
+ * THotSpotCollection class.
+ *
+ * THotSpotCollection represents a collection of hotspots in an imagemap.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class THotSpotCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only {@link THotSpot}.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a THotSpot.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof THotSpot)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('hotspotcollection_hotspot_required');
+ }
+}
+
+
+/**
+ * THotSpot class.
+ *
+ * THotSpot implements the basic functionality common to all hot spot shapes.
+ * Derived classes include {@link TCircleHotSpot}, {@link TPolygonHotSpot}
+ * and {@link TRectangleHotSpot}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class THotSpot extends TComponent
+{
+ private $_viewState=array();
+
+ /**
+ * Returns a viewstate value.
+ *
+ * This function is very useful in defining getter functions for component properties
+ * that must be kept in viewstate.
+ * @param string the name of the viewstate value to be returned
+ * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
+ * @return mixed the viewstate value corresponding to $key
+ */
+ protected function getViewState($key,$defaultValue=null)
+ {
+ return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
+ }
+
+ /**
+ * Sets a viewstate value.
+ *
+ * This function is very useful in defining setter functions for control properties
+ * that must be kept in viewstate.
+ * Make sure that the viewstate value must be serializable and unserializable.
+ * @param string the name of the viewstate value
+ * @param mixed the viewstate value to be set
+ * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
+ */
+ protected function setViewState($key,$value,$defaultValue=null)
+ {
+ if($value===$defaultValue)
+ unset($this->_viewState[$key]);
+ else
+ $this->_viewState[$key]=$value;
+ }
+
+ /**
+ * @return string shape of the hotspot, can be 'circle', 'rect', 'poly', etc.
+ */
+ abstract public function getShape();
+ /**
+ * @return string coordinates defining the hotspot shape.
+ */
+ abstract public function getCoordinates();
+
+ /**
+ * @return string the access key that allows you to quickly navigate to the HotSpot region. Defaults to ''.
+ */
+ public function getAccessKey()
+ {
+ return $this->getViewState('AccessKey','');
+ }
+
+ /**
+ * @param string the access key that allows you to quickly navigate to the HotSpot region.
+ */
+ public function setAccessKey($value)
+ {
+ $this->setViewState('AccessKey',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the alternate text to display for a HotSpot object. Defaults to ''.
+ */
+ public function getAlternateText()
+ {
+ return $this->getViewState('AlternateText','');
+ }
+
+ /**
+ * @param string the alternate text to display for a HotSpot object.
+ */
+ public function setAlternateText($value)
+ {
+ $this->setViewState('AlternateText',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return THotSpotMode the behavior of a HotSpot object when it is clicked. Defaults to THotSpotMode::NotSet.
+ */
+ public function getHotSpotMode()
+ {
+ return $this->getViewState('HotSpotMode',THotSpotMode::NotSet);
+ }
+
+ /**
+ * @param THotSpotMode the behavior of a HotSpot object when it is clicked.
+ */
+ public function setHotSpotMode($value)
+ {
+ $this->setViewState('HotSpotMode',TPropertyValue::ensureEnum($value,'THotSpotMode'),THotSpotMode::NotSet);
+ }
+
+ /**
+ * @return string the URL to navigate to when a HotSpot object is clicked. Defaults to ''.
+ */
+ public function getNavigateUrl()
+ {
+ return $this->getViewState('NavigateUrl','');
+ }
+
+ /**
+ * @param string the URL to navigate to when a HotSpot object is clicked.
+ */
+ public function setNavigateUrl($value)
+ {
+ $this->setViewState('NavigateUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string a value that is post back when the HotSpot is clicked. Defaults to ''.
+ */
+ public function getPostBackValue()
+ {
+ return $this->getViewState('PostBackValue','');
+ }
+
+ /**
+ * @param string a value that is post back when the HotSpot is clicked.
+ */
+ public function setPostBackValue($value)
+ {
+ $this->setViewState('PostBackValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return integer the tab index of the HotSpot region. Defaults to 0.
+ */
+ public function getTabIndex()
+ {
+ return $this->getViewState('TabIndex',0);
+ }
+
+ /**
+ * @param integer the tab index of the HotSpot region.
+ */
+ public function setTabIndex($value)
+ {
+ $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this hotspot will cause input validation, default is true
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this hotspot will cause input validation
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the hotspot causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the hotspot causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the target window or frame to display the new page when the HotSpot region
+ * is clicked. Defaults to ''.
+ */
+ public function getTarget()
+ {
+ return $this->getViewState('Target','');
+ }
+
+ /**
+ * @param string the target window or frame to display the new page when the HotSpot region
+ * is clicked.
+ */
+ public function setTarget($value)
+ {
+ $this->setViewState('Target',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return boolean whether the hotspot has custom attributes
+ */
+ public function getHasAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->getCount()>0;
+ else
+ return false;
+ }
+
+ /**
+ * Returns the list of custom attributes.
+ * Custom attributes are name-value pairs that may be rendered
+ * as HTML tags' attributes.
+ * @return TAttributeCollection the list of custom attributes
+ */
+ public function getAttributes()
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes;
+ else
+ {
+ $attributes=new TAttributeCollection;
+ $this->setViewState('Attributes',$attributes,null);
+ return $attributes;
+ }
+ }
+
+ /**
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->contains($name);
+ else
+ return false;
+ }
+
+ /**
+ * @return string attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->itemAt($name);
+ else
+ return null;
+ }
+
+ /**
+ * Sets a custom hotspot attribute.
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, null if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ if($attributes=$this->getViewState('Attributes',null))
+ return $attributes->remove($name);
+ else
+ return null;
+ }
+
+ /**
+ * Renders this hotspot.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ $writer->addAttribute('shape',$this->getShape());
+ $writer->addAttribute('coords',$this->getCoordinates());
+ if(($mode=$this->getHotSpotMode())===THotSpotMode::NotSet)
+ $mode=THotSpotMode::Navigate;
+ if($mode===THotSpotMode::Navigate)
+ {
+ $writer->addAttribute('href',$this->getNavigateUrl());
+ if(($target=$this->getTarget())!=='')
+ $writer->addAttribute('target',$target);
+ }
+ else if($mode===THotSpotMode::Inactive)
+ $writer->addAttribute('nohref','true');
+ $text=$this->getAlternateText();
+ $writer->addAttribute('title',$text);
+ $writer->addAttribute('alt',$text);
+ if(($accessKey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accessKey);
+ if(($tabIndex=$this->getTabIndex())!==0)
+ $writer->addAttribute('tabindex',"$tabIndex");
+ if($this->getHasAttributes())
+ {
+ foreach($this->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ $writer->renderBeginTag('area');
+ $writer->renderEndTag();
+ }
+}
+
+/**
+ * Class TCircleHotSpot.
+ *
+ * TCircleHotSpot defines a circular hot spot region in a {@link TImageMap}
+ * control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCircleHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'circle';
+ }
+
+ /**
+ * @return string coordinates defining this hotspot shape
+ */
+ public function getCoordinates()
+ {
+ return $this->getX().','.$this->getY().','.$this->getRadius();
+ }
+
+ /**
+ * @return integer radius of the circular HotSpot region. Defaults to 0.
+ */
+ public function getRadius()
+ {
+ return $this->getViewState('Radius',0);
+ }
+
+ /**
+ * @param integer radius of the circular HotSpot region.
+ */
+ public function setRadius($value)
+ {
+ $this->setViewState('Radius',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the center of the circular HotSpot region. Defaults to 0.
+ */
+ public function getX()
+ {
+ return $this->getViewState('X',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the center of the circular HotSpot region.
+ */
+ public function setX($value)
+ {
+ $this->setViewState('X',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the Y coordinate of the center of the circular HotSpot region. Defaults to 0.
+ */
+ public function getY()
+ {
+ return $this->getViewState('Y',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the center of the circular HotSpot region.
+ */
+ public function setY($value)
+ {
+ $this->setViewState('Y',TPropertyValue::ensureInteger($value),0);
+ }
+}
+
+/**
+ * Class TRectangleHotSpot.
+ *
+ * TRectangleHotSpot defines a rectangle hot spot region in a {@link
+ * TImageMap} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRectangleHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'rect';
+ }
+
+ /**
+ * @return string coordinates defining this hotspot shape
+ */
+ public function getCoordinates()
+ {
+ return $this->getLeft().','.$this->getTop().','.$this->getRight().','.$this->getBottom();
+ }
+
+ /**
+ * @return integer the Y coordinate of the bottom side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getBottom()
+ {
+ return $this->getViewState('Bottom',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the bottom side of the rectangle HotSpot region.
+ */
+ public function setBottom($value)
+ {
+ $this->setViewState('Bottom',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getLeft()
+ {
+ return $this->getViewState('Left',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the right side of the rectangle HotSpot region.
+ */
+ public function setLeft($value)
+ {
+ $this->setViewState('Left',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the X coordinate of the right side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getRight()
+ {
+ return $this->getViewState('Right',0);
+ }
+
+ /**
+ * @param integer the X coordinate of the right side of the rectangle HotSpot region.
+ */
+ public function setRight($value)
+ {
+ $this->setViewState('Right',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the Y coordinate of the top side of the rectangle HotSpot region. Defaults to 0.
+ */
+ public function getTop()
+ {
+ return $this->getViewState('Top',0);
+ }
+
+ /**
+ * @param integer the Y coordinate of the top side of the rectangle HotSpot region.
+ */
+ public function setTop($value)
+ {
+ $this->setViewState('Top',TPropertyValue::ensureInteger($value),0);
+ }
+}
+
+/**
+ * Class TPolygonHotSpot.
+ *
+ * TPolygonHotSpot defines a polygon hot spot region in a {@link
+ * TImageMap} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPolygonHotSpot extends THotSpot
+{
+ /**
+ * @return string shape of this hotspot.
+ */
+ public function getShape()
+ {
+ return 'poly';
+ }
+
+ /**
+ * @return string coordinates of the vertices defining the polygon.
+ * Coordinates are concatenated together with comma ','. Each pair
+ * represents (x,y) of a vertex.
+ */
+ public function getCoordinates()
+ {
+ return $this->getViewState('Coordinates','');
+ }
+
+ /**
+ * @param string coordinates of the vertices defining the polygon.
+ * Coordinates are concatenated together with comma ','. Each pair
+ * represents (x,y) of a vertex.
+ */
+ public function setCoordinates($value)
+ {
+ $this->setViewState('Coordinates',$value,'');
+ }
+}
+
+
+/**
+ * THotSpotMode class.
+ * THotSpotMode defines the enumerable type for the possible hot spot modes.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the mode is not specified
+ * - Navigate: clicking on the hotspot will redirect the browser to a different page
+ * - PostBack: clicking on the hotspot will cause a postback
+ * - Inactive: the hotspot is inactive (not clickable)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class THotSpotMode extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Navigate='Navigate';
+ const PostBack='PostBack';
+ const Inactive='Inactive';
+}
+
diff --git a/framework/Web/UI/WebControls/TItemDataRenderer.php b/framework/Web/UI/WebControls/TItemDataRenderer.php
index 60b34873..80d7f418 100644
--- a/framework/Web/UI/WebControls/TItemDataRenderer.php
+++ b/framework/Web/UI/WebControls/TItemDataRenderer.php
@@ -1,83 +1,83 @@
-<?php
-/**
- * TItemDataRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TItemDataRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Web.UI.WebControls.TDataRenderer');
-
-/**
- * TItemDataRenderer class
- *
- * TItemDataRenderer is the convient base class for template-based item data renderers.
- * It implements the {@link IItemDataRenderer} interface, and because
- * TItemDataRenderer extends from {@link TTemplateControl}, derived child
- * classes can have templates to define their presentational layout.
- *
- * The following properties are provided by TItemDataRenderer:
- * - {@link getItemIndex ItemIndex}: zero-based index of this renderer in the item list collection.
- * - {@link getItemType ItemType}: item type of this renderer, such as TListItemType::AlternatingItem
- * - {@link getData Data}: data associated with this renderer
-
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.2
- */
-abstract class TItemDataRenderer extends TDataRenderer implements IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of repeater
- */
- private $_itemIndex;
- /**
- * type of the TRepeaterItem
- * @var TListItemType
- */
- private $_itemType;
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Web.UI.WebControls.TDataRenderer');
+
+/**
+ * TItemDataRenderer class
+ *
+ * TItemDataRenderer is the convient base class for template-based item data renderers.
+ * It implements the {@link IItemDataRenderer} interface, and because
+ * TItemDataRenderer extends from {@link TTemplateControl}, derived child
+ * classes can have templates to define their presentational layout.
+ *
+ * The following properties are provided by TItemDataRenderer:
+ * - {@link getItemIndex ItemIndex}: zero-based index of this renderer in the item list collection.
+ * - {@link getItemType ItemType}: item type of this renderer, such as TListItemType::AlternatingItem
+ * - {@link getData Data}: data associated with this renderer
+
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.2
+ */
+abstract class TItemDataRenderer extends TDataRenderer implements IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of repeater
+ */
+ private $_itemIndex;
+ /**
+ * type of the TRepeaterItem
+ * @var TListItemType
+ */
+ private $_itemType;
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TJavascriptLogger.php b/framework/Web/UI/WebControls/TJavascriptLogger.php
index e0d695f4..3b430357 100644
--- a/framework/Web/UI/WebControls/TJavascriptLogger.php
+++ b/framework/Web/UI/WebControls/TJavascriptLogger.php
@@ -1,93 +1,93 @@
-<?php
-/**
- * TJavascriptLogger class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TJavascriptLogger class.
- *
- * Provides logging for client-side javascript. Example: template code
- * <code><com:TJavascriptLogger /></code>
- *
- * Client-side javascript code to log info, error, warn, debug
- * <code>Logger.warn('A warning');
- * Logger.info('something happend');
- * </code>
- *
- * To see the logger and console, press ALT-D (or CTRL-D on OS X).
- * More information on the logger can be found at
- * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
- *
- * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TJavascriptLogger extends TWebControl
-{
- private static $_keyCodes = array(
- '0'=>48, '1'=>49, '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57,
- 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, 'h'=>72,
- 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, 'p'=>80,
- 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, 'x'=>88, 'y'=>89, 'z'=>90);
-
- /**
- * @return string tag name of the panel
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * @param string keyboard key for toggling the console, default is J.
- */
- public function setToggleKey($value)
- {
- $this->setViewState('ToggleKey', $value, 'j');
- }
-
- /**
- * @return string keyboard key for toggling the console.
- */
- public function getToggleKey()
- {
- return $this->getViewState('ToggleKey', 'j');
- }
-
- /**
- * Registers the required logger javascript.
- * @param TEventParameter event parameter
- */
- public function onPreRender($param)
- {
- $key = strtolower($this->getToggleKey());
- $code = isset(self::$_keyCodes[$key]) ? self::$_keyCodes[$key] : 74;
- $js = "var logConsole; Event.OnLoad(function() { logConsole = new LogConsole($code)}); ";
- $cs = $this->getPage()->getClientScript();
- $cs->registerBeginScript($this->getClientID(),$js);
- $cs->registerPradoScript('logger');
- }
-
- /**
- * Register the required javascript libraries and
- * display some general usage information.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- $code = strtoupper($this->getToggleKey());
- $info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
- $link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>';
- $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
- $writer->write("{$usage} {$link} {$info}");
- }
-}
-
+<?php
+/**
+ * TJavascriptLogger class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TJavascriptLogger class.
+ *
+ * Provides logging for client-side javascript. Example: template code
+ * <code><com:TJavascriptLogger /></code>
+ *
+ * Client-side javascript code to log info, error, warn, debug
+ * <code>Logger.warn('A warning');
+ * Logger.info('something happend');
+ * </code>
+ *
+ * To see the logger and console, press ALT-D (or CTRL-D on OS X).
+ * More information on the logger can be found at
+ * http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/
+ *
+ * @author Wei Zhuo<weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TJavascriptLogger extends TWebControl
+{
+ private static $_keyCodes = array(
+ '0'=>48, '1'=>49, '2'=>50, '3'=>51, '4'=>52, '5'=>53, '6'=>54, '7'=>55, '8'=>56, '9'=>57,
+ 'a'=>65, 'b'=>66, 'c'=>67, 'd'=>68, 'e'=>69, 'f'=>70, 'g'=>71, 'h'=>72,
+ 'i'=>73, 'j'=>74, 'k'=>75, 'l'=>76, 'm'=>77, 'n'=>78, 'o'=>79, 'p'=>80,
+ 'q'=>81, 'r'=>82, 's'=>83, 't'=>84, 'u'=>85, 'v'=>86, 'w'=>87, 'x'=>88, 'y'=>89, 'z'=>90);
+
+ /**
+ * @return string tag name of the panel
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * @param string keyboard key for toggling the console, default is J.
+ */
+ public function setToggleKey($value)
+ {
+ $this->setViewState('ToggleKey', $value, 'j');
+ }
+
+ /**
+ * @return string keyboard key for toggling the console.
+ */
+ public function getToggleKey()
+ {
+ return $this->getViewState('ToggleKey', 'j');
+ }
+
+ /**
+ * Registers the required logger javascript.
+ * @param TEventParameter event parameter
+ */
+ public function onPreRender($param)
+ {
+ $key = strtolower($this->getToggleKey());
+ $code = isset(self::$_keyCodes[$key]) ? self::$_keyCodes[$key] : 74;
+ $js = "var logConsole; Event.OnLoad(function() { logConsole = new LogConsole($code)}); ";
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerBeginScript($this->getClientID(),$js);
+ $cs->registerPradoScript('logger');
+ }
+
+ /**
+ * Register the required javascript libraries and
+ * display some general usage information.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ $code = strtoupper($this->getToggleKey());
+ $info = '(<a href="http://web.archive.org/web/20060512041505/gleepglop.com/javascripts/logger/" target="_blank">more info</a>).';
+ $link = '<a href="javascript:if(logConsole)logConsole.toggle()">toggle the javascript log console.</a>';
+ $usage = 'Press ALT-'.$code.' (Or CTRL-'.$code.' on OS X) to';
+ $writer->write("{$usage} {$link} {$info}");
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TKeyboard.php b/framework/Web/UI/WebControls/TKeyboard.php
index 27cb55c5..58c80e26 100644
--- a/framework/Web/UI/WebControls/TKeyboard.php
+++ b/framework/Web/UI/WebControls/TKeyboard.php
@@ -1,189 +1,189 @@
-<?php
-/**
- * TKeyboard class file.
- *
- * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-
-/**
- * Class TKeyboard.
- *
- * TKeyboard displays a virtual keyboard that users can click on to enter input in
- * an associated text box. It helps to reduce the keyboard recording hacking.
- *
- * To use TKeyboard, write a template like following:
- * <code>
- * <com:TTextBox ID="PasswordInput" />
- * <com:TKeyboard ForControl="PasswordInput" />
- * </code>
- *
- * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl}
- * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when
- * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to
- * false to keep the keyboard showing all the time.
- *
- * The appearance of the keyboard can also be changed by specifying a customized CSS file via
- * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may
- * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}.
- *
- * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TKeyboard extends TWebControl
-{
- /**
- * @return string the ID path of the {@link TTextBox} control
- */
- public function getForControl()
- {
- return $this->getViewState('ForControl','');
- }
-
- /**
- * Sets the ID path of the {@link TTextBox} control.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the keyboard's naming container to the target control.
- * @param string the ID path
- */
- public function setForControl($value)
- {
- $this->setViewState('ForControl', TPropertyValue::ensureString($value));
- }
-
- /**
- * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true.
- */
- public function getAutoHide()
- {
- return $this->getViewState('AutoHide', true);
- }
-
- /**
- * @param boolean whether the keyboard should be hidden when the textbox is not in focus.
- */
- public function setAutoHide($value)
- {
- $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return string the CSS class name for the keyboard <div> element. Defaults to 'Keyboard'.
- */
- public function getKeyboardCssClass()
- {
- return $this->getViewState('KeyboardCssClass', 'Keyboard');
- }
-
- /**
- * Sets a value indicating the CSS class name for the keyboard <div> element.
- * Note, if you change this property, make sure you also supply a customized CSS file
- * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling.
- * @param string the CSS class name for the keyboard <div> element.
- */
- public function setKeyboardCssClass($value)
- {
- $this->setViewState('KeyboardCssClass', $value, 'Keyboard');
- }
-
- /**
- * @return string the URL for the CSS file to customize the appearance of the keyboard.
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl', '');
- }
-
- /**
- * @param string the URL for the CSS file to customize the appearance of the keyboard.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl', $value, '');
- }
-
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getPage()->getClientSupportsJavaScript())
- {
- $this->registerStyleSheet();
- $this->registerClientScript();
- }
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional TKeyboard specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if($this->getPage()->getClientSupportsJavaScript())
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * Registers the CSS relevant to the TKeyboard.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- if(($url=$this->getCssUrl())==='')
- $url=$this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'keyboard.css');
- $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $options=TJavaScript::encode($this->getClientOptions());
- $className=$this->getClientClassName();
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('keyboard');
- $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);");
- }
-
- /**
- * @return string the Javascript class name for this control
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TKeyboard';
- }
-
- /**
- * @return array the JavaScript options for this control
- */
- protected function getClientOptions()
- {
- if(($forControl=$this->getForControl())==='')
- throw new TConfigurationException('keyboard_forcontrol_required');
- if(($target=$this->findControl($forControl))===null)
- throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl);
-
- $options['ID'] = $this->getClientID();
- $options['ForControl'] = $target->getClientID();
- $options['AutoHide'] = $this->getAutoHide();
- $options['CssClass'] = $this->getKeyboardCssClass();
-
- return $options;
- }
-}
-
+<?php
+/**
+ * TKeyboard class file.
+ *
+ * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+
+/**
+ * Class TKeyboard.
+ *
+ * TKeyboard displays a virtual keyboard that users can click on to enter input in
+ * an associated text box. It helps to reduce the keyboard recording hacking.
+ *
+ * To use TKeyboard, write a template like following:
+ * <code>
+ * <com:TTextBox ID="PasswordInput" />
+ * <com:TKeyboard ForControl="PasswordInput" />
+ * </code>
+ *
+ * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl}
+ * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when
+ * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to
+ * false to keep the keyboard showing all the time.
+ *
+ * The appearance of the keyboard can also be changed by specifying a customized CSS file via
+ * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may
+ * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}.
+ *
+ * @author Sergey Morkovkin <sergeymorkovkin@mail.ru> and Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TKeyboard extends TWebControl
+{
+ /**
+ * @return string the ID path of the {@link TTextBox} control
+ */
+ public function getForControl()
+ {
+ return $this->getViewState('ForControl','');
+ }
+
+ /**
+ * Sets the ID path of the {@link TTextBox} control.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the keyboard's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setForControl($value)
+ {
+ $this->setViewState('ForControl', TPropertyValue::ensureString($value));
+ }
+
+ /**
+ * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true.
+ */
+ public function getAutoHide()
+ {
+ return $this->getViewState('AutoHide', true);
+ }
+
+ /**
+ * @param boolean whether the keyboard should be hidden when the textbox is not in focus.
+ */
+ public function setAutoHide($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return string the CSS class name for the keyboard <div> element. Defaults to 'Keyboard'.
+ */
+ public function getKeyboardCssClass()
+ {
+ return $this->getViewState('KeyboardCssClass', 'Keyboard');
+ }
+
+ /**
+ * Sets a value indicating the CSS class name for the keyboard <div> element.
+ * Note, if you change this property, make sure you also supply a customized CSS file
+ * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling.
+ * @param string the CSS class name for the keyboard <div> element.
+ */
+ public function setKeyboardCssClass($value)
+ {
+ $this->setViewState('KeyboardCssClass', $value, 'Keyboard');
+ }
+
+ /**
+ * @return string the URL for the CSS file to customize the appearance of the keyboard.
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl', '');
+ }
+
+ /**
+ * @param string the URL for the CSS file to customize the appearance of the keyboard.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl', $value, '');
+ }
+
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getPage()->getClientSupportsJavaScript())
+ {
+ $this->registerStyleSheet();
+ $this->registerClientScript();
+ }
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional TKeyboard specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if($this->getPage()->getClientSupportsJavaScript())
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * Registers the CSS relevant to the TKeyboard.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ if(($url=$this->getCssUrl())==='')
+ $url=$this->getApplication()->getAssetManager()->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'keyboard.css');
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $options=TJavaScript::encode($this->getClientOptions());
+ $className=$this->getClientClassName();
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('keyboard');
+ $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);");
+ }
+
+ /**
+ * @return string the Javascript class name for this control
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TKeyboard';
+ }
+
+ /**
+ * @return array the JavaScript options for this control
+ */
+ protected function getClientOptions()
+ {
+ if(($forControl=$this->getForControl())==='')
+ throw new TConfigurationException('keyboard_forcontrol_required');
+ if(($target=$this->findControl($forControl))===null)
+ throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl);
+
+ $options['ID'] = $this->getClientID();
+ $options['ForControl'] = $target->getClientID();
+ $options['AutoHide'] = $this->getAutoHide();
+ $options['CssClass'] = $this->getKeyboardCssClass();
+
+ return $options;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TLabel.php b/framework/Web/UI/WebControls/TLabel.php
index 31e424e5..7228d588 100644
--- a/framework/Web/UI/WebControls/TLabel.php
+++ b/framework/Web/UI/WebControls/TLabel.php
@@ -1,154 +1,154 @@
-<?php
-/**
- * TLabel class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TLabel class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLabel class
- *
- * TLabel displays a piece of text on a Web page.
- * Use {@link setText Text} property to set the text to be displayed.
- * TLabel will render the contents enclosed within its component tag
- * if {@link setText Text} is empty.
- * To use TLabel as a form label, associate it with a control by setting the
- * {@link setForControl ForControl} property.
- * The associated control must be locatable within the label's naming container.
- * If the associated control is not visible, the label will not be rendered, either.
- *
- * Note, {@link setText Text} will NOT be encoded for rendering.
- * Make sure it does not contain dangerous characters that you want to avoid.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLabel extends TWebControl implements IDataRenderer
-{
- private $_forControl='';
-
- /**
- * @return string tag name of the label, returns 'label' if there is an associated control, 'span' otherwise.
- */
- protected function getTagName()
- {
- return ($this->getForControl()==='')?'span':'label';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- * @throws TInvalidDataValueException if associated control cannot be found using the ID
- */
- protected function addAttributesToRender($writer)
- {
- if($this->_forControl!=='')
- $writer->addAttribute('for',$this->_forControl);
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the label.
- * It overrides the parent implementation by checking if an associated
- * control is visible or not. If not, the label will not be rendered.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if(($aid=$this->getForControl())!=='')
- {
- if($control=$this->findControl($aid))
- {
- if($control->getVisible(true))
- {
- $this->_forControl=$control->getClientID();
- parent::render($writer);
- }
- }
- else
- throw new TInvalidDataValueException('label_associatedcontrol_invalid',$aid);
- }
- else
- parent::render($writer);
- }
-
- /**
- * Renders the body content of the label.
- * @param THtmlWriter the renderer
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string the text value of the label
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string the text value of the label
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the text value of the label.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text value of the label
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text value of the label.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text value of the label
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the associated control ID
- */
- public function getForControl()
- {
- return $this->getViewState('ForControl','');
- }
-
- /**
- * Sets the ID of the control that the label is associated with.
- * The control must be locatable via {@link TControl::findControl} using the ID.
- * @param string the associated control ID
- */
- public function setForControl($value)
- {
- $this->setViewState('ForControl',$value,'');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLabel class
+ *
+ * TLabel displays a piece of text on a Web page.
+ * Use {@link setText Text} property to set the text to be displayed.
+ * TLabel will render the contents enclosed within its component tag
+ * if {@link setText Text} is empty.
+ * To use TLabel as a form label, associate it with a control by setting the
+ * {@link setForControl ForControl} property.
+ * The associated control must be locatable within the label's naming container.
+ * If the associated control is not visible, the label will not be rendered, either.
+ *
+ * Note, {@link setText Text} will NOT be encoded for rendering.
+ * Make sure it does not contain dangerous characters that you want to avoid.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLabel extends TWebControl implements IDataRenderer
+{
+ private $_forControl='';
+
+ /**
+ * @return string tag name of the label, returns 'label' if there is an associated control, 'span' otherwise.
+ */
+ protected function getTagName()
+ {
+ return ($this->getForControl()==='')?'span':'label';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ * @throws TInvalidDataValueException if associated control cannot be found using the ID
+ */
+ protected function addAttributesToRender($writer)
+ {
+ if($this->_forControl!=='')
+ $writer->addAttribute('for',$this->_forControl);
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the label.
+ * It overrides the parent implementation by checking if an associated
+ * control is visible or not. If not, the label will not be rendered.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if(($aid=$this->getForControl())!=='')
+ {
+ if($control=$this->findControl($aid))
+ {
+ if($control->getVisible(true))
+ {
+ $this->_forControl=$control->getClientID();
+ parent::render($writer);
+ }
+ }
+ else
+ throw new TInvalidDataValueException('label_associatedcontrol_invalid',$aid);
+ }
+ else
+ parent::render($writer);
+ }
+
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the renderer
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string the text value of the label
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string the text value of the label
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the text value of the label.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text value of the label
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text value of the label.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text value of the label
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the associated control ID
+ */
+ public function getForControl()
+ {
+ return $this->getViewState('ForControl','');
+ }
+
+ /**
+ * Sets the ID of the control that the label is associated with.
+ * The control must be locatable via {@link TControl::findControl} using the ID.
+ * @param string the associated control ID
+ */
+ public function setForControl($value)
+ {
+ $this->setViewState('ForControl',$value,'');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TLinkButton.php b/framework/Web/UI/WebControls/TLinkButton.php
index 9da5ec59..f03f9098 100644
--- a/framework/Web/UI/WebControls/TLinkButton.php
+++ b/framework/Web/UI/WebControls/TLinkButton.php
@@ -1,334 +1,334 @@
-<?php
-/**
- * TLinkButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TLinkButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLinkButton class
- *
- * TLinkButton creates a hyperlink style button on the page.
- * TLinkButton has the same appearance as a hyperlink. However, it is mainly
- * used to submit data to a page. Like {@link TButton}, you can create either
- * a <b>submit</b> button or a <b>command</b> button.
- *
- * A <b>command</b> button has a command name (specified by
- * the {@link setCommandName CommandName} property) and and a command parameter
- * (specified by {@link setCommandParameter CommandParameter} property)
- * associated with the button. This allows you to create multiple TLinkButton
- * components on a Web page and programmatically determine which one is clicked
- * with what parameter. You can provide an event handler for
- * {@link onCommand OnCommand} event to programmatically control the actions performed
- * when the command button is clicked. In the event handler, you can determine
- * the {@link setCommandName CommandName} property value and
- * the {@link setCommandParameter CommandParameter} property value
- * through the {@link TCommandParameter::getName Name} and
- * {@link TCommandParameter::getParameter Parameter} properties of the event
- * parameter which is of type {@link TCommandEventParameter}.
- *
- * A <b>submit</b> button does not have a command name associated with the button
- * and clicking on it simply posts the Web page back to the server.
- * By default, a TLinkButton component is a submit button.
- * You can provide an event handler for the {@link onClick OnClick} event
- * to programmatically control the actions performed when the submit button is clicked.
- *
- * Clicking on button can trigger form validation, if
- * {@link setCausesValidation CausesValidation} is true.
- * And the validation may be restricted within a certain group of validator
- * controls by setting {@link setValidationGroup ValidationGroup} property.
- * If validation is successful, the data will be post back to the same page.
- *
- * TLinkButton will display the {@link setText Text} property value
- * as the hyperlink text. If {@link setText Text} is empty, the body content
- * of TLinkButton will be displayed. Therefore, you can use TLinkButton
- * as an image button by enclosing an &lt;img&gt; tag as the body of TLinkButton.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLinkButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
-{
- /**
- * @return string tag name of the button
- */
- protected function getTagName()
- {
- return 'a';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This overrides the parent implementation with additional button specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
-
- $writer->addAttribute('id',$this->getClientID());
-
- // We call parent implementation here because some attributes
- // may be overwritten in the following
- parent::addAttributesToRender($writer);
-
- if($this->getEnabled(true) && $this->getEnableClientScript())
- {
- $this->renderLinkButtonHref($writer);
- $this->renderClientControlScript($writer);
- }
- else if($this->getEnabled()) // in this case, parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- }
-
- /**
- * Renders the client-script code.
- * @param THtmlWriter renderer
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * @param boolean set by a panel to register this button as the default button for the panel.
- */
- public function setIsDefaultButton($value)
- {
- $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true if this button is registered as a default button for a panel.
- */
- public function getIsDefaultButton()
- {
- return $this->getViewState('IsDefaultButton', false);
- }
-
- /**
- * Renders the Href for link button.
- * @param THtmlWriter renderer
- */
- protected function renderLinkButtonHref($writer)
- {
- //create unique no-op url references
- $nop = "javascript:;//".$this->getClientID();
- $writer->addAttribute('href', $nop);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TLinkButton';
- }
-
- /**
- * Returns postback specifications for the button.
- * This method is used by framework and control developers.
- * @return array parameters about how the button defines its postback behavior.
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['StopEvent'] = true;
-
- return $options;
- }
-
- /**
- * Renders the body content enclosed between the control tag.
- * If {@link getText Text} is not empty, it will be rendered. Otherwise,
- * the body content enclosed in the control tag will be rendered.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='')
- parent::renderContents($writer);
- else
- $writer->write($text);
- }
-
- /**
- * @return string the text caption of the button
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string the text caption to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string caption of the button.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the caption of the button.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string caption of the button
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function getCommandName()
- {
- return $this->getViewState('CommandName','');
- }
-
- /**
- * @param string the command name associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandName($value)
- {
- $this->setViewState('CommandName',$value,'');
- }
-
- /**
- * @return string the parameter associated with the {@link onCommand OnCommand} event
- */
- public function getCommandParameter()
- {
- return $this->getViewState('CommandParameter','');
- }
-
- /**
- * @param string the parameter associated with the {@link onCommand OnCommand} event.
- */
- public function setCommandParameter($value)
- {
- $this->setViewState('CommandParameter',$value,'');
- }
-
- /**
- * @return boolean whether postback event trigger by this button will cause input validation
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * Sets the value indicating whether postback event trigger by this button will cause input validation.
- * @param string the text caption to be set
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the group of validators which the button causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the button causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * Raises the postback event.
- * This method is required by {@link IPostBackEventHandler} interface.
- * If {@link getCausesValidation CausesValidation} is true, it will
- * invoke the page's {@link TPage::validate validate} method first.
- * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
- * This method is mainly used by framework and control developers.
- * @param TEventParameter the event parameter
- */
- public function raisePostBackEvent($param)
- {
- if($this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onClick(null);
- $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnClick' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handler can be invoked.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onClick($param)
- {
- $this->raiseEvent('OnClick',$this,$param);
- }
-
- /**
- * This method is invoked when the button is clicked.
- * The method raises 'OnCommand' event to fire up the event handlers.
- * If you override this method, be sure to call the parent implementation
- * so that the event handlers can be invoked.
- * @param TCommandEventParameter event parameter to be passed to the event handlers
- */
- public function onCommand($param)
- {
- $this->raiseEvent('OnCommand',$this,$param);
- $this->raiseBubbleEvent($this,$param);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLinkButton class
+ *
+ * TLinkButton creates a hyperlink style button on the page.
+ * TLinkButton has the same appearance as a hyperlink. However, it is mainly
+ * used to submit data to a page. Like {@link TButton}, you can create either
+ * a <b>submit</b> button or a <b>command</b> button.
+ *
+ * A <b>command</b> button has a command name (specified by
+ * the {@link setCommandName CommandName} property) and and a command parameter
+ * (specified by {@link setCommandParameter CommandParameter} property)
+ * associated with the button. This allows you to create multiple TLinkButton
+ * components on a Web page and programmatically determine which one is clicked
+ * with what parameter. You can provide an event handler for
+ * {@link onCommand OnCommand} event to programmatically control the actions performed
+ * when the command button is clicked. In the event handler, you can determine
+ * the {@link setCommandName CommandName} property value and
+ * the {@link setCommandParameter CommandParameter} property value
+ * through the {@link TCommandParameter::getName Name} and
+ * {@link TCommandParameter::getParameter Parameter} properties of the event
+ * parameter which is of type {@link TCommandEventParameter}.
+ *
+ * A <b>submit</b> button does not have a command name associated with the button
+ * and clicking on it simply posts the Web page back to the server.
+ * By default, a TLinkButton component is a submit button.
+ * You can provide an event handler for the {@link onClick OnClick} event
+ * to programmatically control the actions performed when the submit button is clicked.
+ *
+ * Clicking on button can trigger form validation, if
+ * {@link setCausesValidation CausesValidation} is true.
+ * And the validation may be restricted within a certain group of validator
+ * controls by setting {@link setValidationGroup ValidationGroup} property.
+ * If validation is successful, the data will be post back to the same page.
+ *
+ * TLinkButton will display the {@link setText Text} property value
+ * as the hyperlink text. If {@link setText Text} is empty, the body content
+ * of TLinkButton will be displayed. Therefore, you can use TLinkButton
+ * as an image button by enclosing an &lt;img&gt; tag as the body of TLinkButton.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLinkButton extends TWebControl implements IPostBackEventHandler, IButtonControl, IDataRenderer
+{
+ /**
+ * @return string tag name of the button
+ */
+ protected function getTagName()
+ {
+ return 'a';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This overrides the parent implementation with additional button specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+
+ $writer->addAttribute('id',$this->getClientID());
+
+ // We call parent implementation here because some attributes
+ // may be overwritten in the following
+ parent::addAttributesToRender($writer);
+
+ if($this->getEnabled(true) && $this->getEnableClientScript())
+ {
+ $this->renderLinkButtonHref($writer);
+ $this->renderClientControlScript($writer);
+ }
+ else if($this->getEnabled()) // in this case, parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ }
+
+ /**
+ * Renders the client-script code.
+ * @param THtmlWriter renderer
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * @param boolean set by a panel to register this button as the default button for the panel.
+ */
+ public function setIsDefaultButton($value)
+ {
+ $this->setViewState('IsDefaultButton', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true if this button is registered as a default button for a panel.
+ */
+ public function getIsDefaultButton()
+ {
+ return $this->getViewState('IsDefaultButton', false);
+ }
+
+ /**
+ * Renders the Href for link button.
+ * @param THtmlWriter renderer
+ */
+ protected function renderLinkButtonHref($writer)
+ {
+ //create unique no-op url references
+ $nop = "javascript:;//".$this->getClientID();
+ $writer->addAttribute('href', $nop);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TLinkButton';
+ }
+
+ /**
+ * Returns postback specifications for the button.
+ * This method is used by framework and control developers.
+ * @return array parameters about how the button defines its postback behavior.
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['StopEvent'] = true;
+
+ return $options;
+ }
+
+ /**
+ * Renders the body content enclosed between the control tag.
+ * If {@link getText Text} is not empty, it will be rendered. Otherwise,
+ * the body content enclosed in the control tag will be rendered.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
+ }
+
+ /**
+ * @return string the text caption of the button
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string the text caption to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string caption of the button.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the caption of the button.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string caption of the button
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function getCommandName()
+ {
+ return $this->getViewState('CommandName','');
+ }
+
+ /**
+ * @param string the command name associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandName($value)
+ {
+ $this->setViewState('CommandName',$value,'');
+ }
+
+ /**
+ * @return string the parameter associated with the {@link onCommand OnCommand} event
+ */
+ public function getCommandParameter()
+ {
+ return $this->getViewState('CommandParameter','');
+ }
+
+ /**
+ * @param string the parameter associated with the {@link onCommand OnCommand} event.
+ */
+ public function setCommandParameter($value)
+ {
+ $this->setViewState('CommandParameter',$value,'');
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this button will cause input validation
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * Sets the value indicating whether postback event trigger by this button will cause input validation.
+ * @param string the text caption to be set
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the group of validators which the button causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the button causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * Raises the postback event.
+ * This method is required by {@link IPostBackEventHandler} interface.
+ * If {@link getCausesValidation CausesValidation} is true, it will
+ * invoke the page's {@link TPage::validate validate} method first.
+ * It will raise {@link onClick OnClick} and {@link onCommand OnCommand} events.
+ * This method is mainly used by framework and control developers.
+ * @param TEventParameter the event parameter
+ */
+ public function raisePostBackEvent($param)
+ {
+ if($this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onClick(null);
+ $this->onCommand(new TCommandEventParameter($this->getCommandName(),$this->getCommandParameter()));
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnClick' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handler can be invoked.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onClick($param)
+ {
+ $this->raiseEvent('OnClick',$this,$param);
+ }
+
+ /**
+ * This method is invoked when the button is clicked.
+ * The method raises 'OnCommand' event to fire up the event handlers.
+ * If you override this method, be sure to call the parent implementation
+ * so that the event handlers can be invoked.
+ * @param TCommandEventParameter event parameter to be passed to the event handlers
+ */
+ public function onCommand($param)
+ {
+ $this->raiseEvent('OnCommand',$this,$param);
+ $this->raiseBubbleEvent($this,$param);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TListBox.php b/framework/Web/UI/WebControls/TListBox.php
index 8e996b6e..f7ab4791 100644
--- a/framework/Web/UI/WebControls/TListBox.php
+++ b/framework/Web/UI/WebControls/TListBox.php
@@ -1,226 +1,226 @@
-<?php
-/**
- * TListBox class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TListBox class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TListControl class
- */
-Prado::using('System.Web.UI.WebControls.TListControl');
-
-/**
- * TListBox class
- *
- * TListBox displays a list box on a Web page that allows single or multiple selection.
- * The list box allows multiple selections if {@link setSelectionMode SelectionMode}
- * is TListSelectionMode::Multiple. It takes single selection only if Single.
- * The property {@link setRows Rows} specifies how many rows of options are visible
- * at a time. See {@link TListControl} for inherited properties.
- *
- * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for
- * a list item, set a Group attribute with it,
- * <code>
- * $listitem->Attributes->Group="Group Name";
- * // or <com:TListItem Attributes.Group="Group Name" .../> in template
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListBox extends TListControl implements IPostBackDataHandler, IValidatable
-{
- private $_dataChanged=false;
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TListControl class
+ */
+Prado::using('System.Web.UI.WebControls.TListControl');
+
+/**
+ * TListBox class
+ *
+ * TListBox displays a list box on a Web page that allows single or multiple selection.
+ * The list box allows multiple selections if {@link setSelectionMode SelectionMode}
+ * is TListSelectionMode::Multiple. It takes single selection only if Single.
+ * The property {@link setRows Rows} specifies how many rows of options are visible
+ * at a time. See {@link TListControl} for inherited properties.
+ *
+ * Since v3.0.3, TListBox starts to support optgroup. To specify an option group for
+ * a list item, set a Group attribute with it,
+ * <code>
+ * $listitem->Attributes->Group="Group Name";
+ * // or <com:TListItem Attributes.Group="Group Name" .../> in template
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListBox extends TListControl implements IPostBackDataHandler, IValidatable
+{
+ private $_dataChanged=false;
private $_isValid=true;
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional list box specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $rows=$this->getRows();
- $writer->addAttribute('size',"$rows");
- if($this->getSelectionMode()===TListSelectionMode::Multiple)
- $writer->addAttribute('name',$this->getUniqueID().'[]');
- else
- $writer->addAttribute('name',$this->getUniqueID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListBox';
- }
-
- /**
- * Registers the list control to load post data on postback.
- * This method overrides the parent implementation.
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- if($this->getEnabled(true))
- $this->getPage()->registerRequiresPostData($this);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- if(!$this->getEnabled(true))
- return false;
- $this->ensureDataBound();
- $selections=isset($values[$key])?$values[$key]:null;
- if($selections!==null)
- {
- $items=$this->getItems();
- if($this->getSelectionMode()===TListSelectionMode::Single)
- {
- $selection=is_array($selections)?$selections[0]:$selections;
- $index=$items->findIndexByValue($selection,false);
- if($this->getSelectedIndex()!==$index)
- {
- $this->setSelectedIndex($index);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
- if(!is_array($selections))
- $selections=array($selections);
- $list=array();
- foreach($selections as $selection)
- $list[]=$items->findIndexByValue($selection,false);
- $list2=$this->getSelectedIndices();
- $n=count($list);
- $flag=false;
- if($n===count($list2))
- {
- sort($list,SORT_NUMERIC);
- for($i=0;$i<$n;++$i)
- {
- if($list[$i]!==$list2[$i])
- {
- $flag=true;
- break;
- }
- }
- }
- else
- $flag=true;
- if($flag)
- {
- $this->setSelectedIndices($list);
- $this->_dataChanged=true;
- }
- return $flag;
- }
- else if($this->getSelectedIndex()!==-1)
- {
- $this->clearSelection();
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onSelectedIndexChanged(null);
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * @return boolean whether this control allows multiple selection
- */
- protected function getIsMultiSelect()
- {
- return $this->getSelectionMode()===TListSelectionMode::Multiple;
- }
-
- /**
- * @return integer the number of rows to be displayed in the list control
- */
- public function getRows()
- {
- return $this->getViewState('Rows', 4);
- }
-
- /**
- * @param integer the number of rows to be displayed in the list control
- */
- public function setRows($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- if($value<=0)
- $value=4;
- $this->setViewState('Rows', $value, 4);
- }
-
- /**
- * @return TListSelectionMode the selection mode (Single, Multiple). Defaults to TListSelectionMode::Single.
- */
- public function getSelectionMode()
- {
- return $this->getViewState('SelectionMode', TListSelectionMode::Single);
- }
-
- /**
- * @param TListSelectionMode the selection mode
- */
- public function setSelectionMode($value)
- {
- $this->setViewState('SelectionMode',TPropertyValue::ensureEnum($value,'TListSelectionMode'),TListSelectionMode::Single);
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getSelectedValue();
- }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional list box specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $rows=$this->getRows();
+ $writer->addAttribute('size',"$rows");
+ if($this->getSelectionMode()===TListSelectionMode::Multiple)
+ $writer->addAttribute('name',$this->getUniqueID().'[]');
+ else
+ $writer->addAttribute('name',$this->getUniqueID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListBox';
+ }
+
+ /**
+ * Registers the list control to load post data on postback.
+ * This method overrides the parent implementation.
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ if($this->getEnabled(true))
+ $this->getPage()->registerRequiresPostData($this);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ if(!$this->getEnabled(true))
+ return false;
+ $this->ensureDataBound();
+ $selections=isset($values[$key])?$values[$key]:null;
+ if($selections!==null)
+ {
+ $items=$this->getItems();
+ if($this->getSelectionMode()===TListSelectionMode::Single)
+ {
+ $selection=is_array($selections)?$selections[0]:$selections;
+ $index=$items->findIndexByValue($selection,false);
+ if($this->getSelectedIndex()!==$index)
+ {
+ $this->setSelectedIndex($index);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+ if(!is_array($selections))
+ $selections=array($selections);
+ $list=array();
+ foreach($selections as $selection)
+ $list[]=$items->findIndexByValue($selection,false);
+ $list2=$this->getSelectedIndices();
+ $n=count($list);
+ $flag=false;
+ if($n===count($list2))
+ {
+ sort($list,SORT_NUMERIC);
+ for($i=0;$i<$n;++$i)
+ {
+ if($list[$i]!==$list2[$i])
+ {
+ $flag=true;
+ break;
+ }
+ }
+ }
+ else
+ $flag=true;
+ if($flag)
+ {
+ $this->setSelectedIndices($list);
+ $this->_dataChanged=true;
+ }
+ return $flag;
+ }
+ else if($this->getSelectedIndex()!==-1)
+ {
+ $this->clearSelection();
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getSelectedIndices SelectedIndices} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onSelectedIndexChanged(null);
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * @return boolean whether this control allows multiple selection
+ */
+ protected function getIsMultiSelect()
+ {
+ return $this->getSelectionMode()===TListSelectionMode::Multiple;
+ }
+
+ /**
+ * @return integer the number of rows to be displayed in the list control
+ */
+ public function getRows()
+ {
+ return $this->getViewState('Rows', 4);
+ }
+
+ /**
+ * @param integer the number of rows to be displayed in the list control
+ */
+ public function setRows($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ if($value<=0)
+ $value=4;
+ $this->setViewState('Rows', $value, 4);
+ }
+
+ /**
+ * @return TListSelectionMode the selection mode (Single, Multiple). Defaults to TListSelectionMode::Single.
+ */
+ public function getSelectionMode()
+ {
+ return $this->getViewState('SelectionMode', TListSelectionMode::Single);
+ }
+
+ /**
+ * @param TListSelectionMode the selection mode
+ */
+ public function setSelectionMode($value)
+ {
+ $this->setViewState('SelectionMode',TPropertyValue::ensureEnum($value,'TListSelectionMode'),TListSelectionMode::Single);
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getSelectedValue();
+ }
/**
* Returns true if this control validated successfully.
@@ -238,25 +238,25 @@ class TListBox extends TListControl implements IPostBackDataHandler, IValidatabl
{
$this->_isValid=TPropertyValue::ensureBoolean($value);
}
-}
-
-
-/**
- * TListSelectionMode class.
- * TListSelectionMode defines the enumerable type for the possible selection modes of a {@link TListBox}.
- *
- * The following enumerable values are defined:
- * - Single: single selection
- * - Multiple: allow multiple selection
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TListSelectionMode extends TEnumerable
-{
- const Single='Single';
- const Multiple='Multiple';
-}
-
+}
+
+
+/**
+ * TListSelectionMode class.
+ * TListSelectionMode defines the enumerable type for the possible selection modes of a {@link TListBox}.
+ *
+ * The following enumerable values are defined:
+ * - Single: single selection
+ * - Multiple: allow multiple selection
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TListSelectionMode extends TEnumerable
+{
+ const Single='Single';
+ const Multiple='Multiple';
+}
+
diff --git a/framework/Web/UI/WebControls/TListControl.php b/framework/Web/UI/WebControls/TListControl.php
index 1a07a292..4d388d45 100644
--- a/framework/Web/UI/WebControls/TListControl.php
+++ b/framework/Web/UI/WebControls/TListControl.php
@@ -1,923 +1,923 @@
-<?php
-
-/**
- * TListControl class file
- *
- * @author Robin J. Rogge <rojaro@gmail.com>
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes the supporting classes
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Web.UI.WebControls.TListItem');
-Prado::using('System.Collections.TListItemCollection');
-Prado::using('System.Collections.TAttributeCollection');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TListControl class
- *
- * TListControl is a base class for list controls, such as {@link TListBox},
- * {@link TDropDownList}, {@link TCheckBoxList}, etc.
- * It manages the items and their status in a list control.
- * It also implements how the items can be populated from template and
- * data source.
- *
- * The property {@link getItems} returns a list of the items in the control.
- * To specify or determine which item is selected, use the
- * {@link getSelectedIndex SelectedIndex} property that indicates the zero-based
- * index of the selected item in the item list. You may also use
- * {@link getSelectedItem SelectedItem} and {@link getSelectedValue SelectedValue}
- * to get the selected item and its value. For multiple selection lists
- * (such as {@link TCheckBoxList} and {@link TListBox}), property
- * {@link getSelectedIndices SelectedIndices} is useful.
- *
- * TListControl implements {@link setAutoPostBack AutoPostBack} which allows
- * a list control to postback the page if the selections of the list items are changed.
- * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
- * properties may be used to specify that validation be performed when auto postback occurs.
- *
- * There are three ways to populate the items in a list control: from template,
- * using {@link setDataSource DataSource} and using {@link setDataSourceID DataSourceID}.
- * The latter two are covered in {@link TDataBoundControl}. To specify items via
- * template, using the following template syntax:
- * <code>
- * <com:TListControl>
- * <com:TListItem Value="xxx" Text="yyy" >
- * <com:TListItem Value="xxx" Text="yyy" Selected="true" >
- * <com:TListItem Value="xxx" Text="yyy" >
- * </com:TListControl>
- * </code>
- *
- * When {@link setDataSource DataSource} or {@link setDataSourceID DataSourceID}
- * is used to populate list items, the {@link setDataTextField DataTextField} and
- * {@link setDataValueField DataValueField} properties are used to specify which
- * columns of the data will be used to populate the text and value of the items.
- * For example, if a data source is as follows,
- * <code>
- * $dataSource=array(
- * array('name'=>'John', 'age'=>31),
- * array('name'=>'Cary', 'age'=>28),
- * array('name'=>'Rose', 'age'=>35),
- * );
- * </code>
- * setting {@link setDataTextField DataTextField} and {@link setDataValueField DataValueField}
- * to 'name' and 'age' will make the first item's text be 'John', value be 31,
- * the second item's text be 'Cary', value be 28, and so on.
- * The {@link setDataTextFormatString DataTextFormatString} property may be further
- * used to format how the item should be displayed. See {@link formatDataValue()}
- * for an explanation of the format string.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-abstract class TListControl extends TDataBoundControl implements IDataRenderer
-{
- /**
- * @var TListItemCollection item list
- */
- private $_items=null;
- /**
- * @var boolean whether items are restored from viewstate
- */
- private $_stateLoaded=false;
- /**
- * @var mixed the following selection variables are used
- * to keep selections when Items are not available
- */
- private $_cachedSelectedIndex=-1;
- private $_cachedSelectedValue=null;
- private $_cachedSelectedIndices=null;
- private $_cachedSelectedValues=null;
-
- /**
- * @return string tag name of the list control
- */
- protected function getTagName()
- {
- return 'select';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- if($this->getIsMultiSelect())
- $writer->addAttribute('multiple','multiple');
- if($this->getEnabled(true))
- {
- if($this->getAutoPostBack()
- && $this->getEnableClientScript()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- }
- else if($this->getEnabled())
- $writer->addAttribute('disabled','disabled');
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the javascript for list control.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * Derived classes may override this method and return customized js class names.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListControl';
- }
-
- /**
- * @return array postback options for JS postback code
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['EventTarget'] = $this->getUniqueID();
- return $options;
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- // Do not add items from template if items are loaded from viewstate
- if(!$this->_stateLoaded && ($object instanceof TListItem))
- {
- $index=$this->getItems()->add($object);
- if(($this->_cachedSelectedValue!==null && $this->_cachedSelectedValue===$object->getValue()) || ($this->_cachedSelectedIndex===$index))
- {
- $object->setSelected(true);
- $this->_cachedSelectedValue=null;
- $this->_cachedSelectedIndex=-1;
- }
- }
- }
-
- /**
- * Performs databinding to populate list items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $items=$this->getItems();
- if(!$this->getAppendDataBoundItems())
- $items->clear();
- $textField=$this->getDataTextField();
- if($textField==='')
- $textField=0;
- $valueField=$this->getDataValueField();
- if($valueField==='')
- $valueField=1;
- $textFormat=$this->getDataTextFormatString();
- $groupField=$this->getDataGroupField();
- foreach($data as $key=>$object)
- {
- $item=$items->createListItem();
- if(is_array($object) || is_object($object))
- {
- $text=TDataFieldAccessor::getDataFieldValue($object,$textField);
- $value=TDataFieldAccessor::getDataFieldValue($object,$valueField);
- $item->setValue($value);
- if($groupField!=='')
- $item->setAttribute('Group',TDataFieldAccessor::getDataFieldValue($object,$groupField));
- }
- else
- {
- $text=$object;
- $item->setValue("$key");
- }
- $item->setText($this->formatDataValue($textFormat,$text));
- }
- // SelectedValue or SelectedIndex may be set before databinding
- // so we make them be effective now
- if($this->_cachedSelectedValue!==null)
- {
- $this->setSelectedValue($this->_cachedSelectedValue);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedIndex!==-1)
- {
- $this->setSelectedIndex($this->_cachedSelectedIndex);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedValues!==null)
- {
- $this->setSelectedValues($this->_cachedSelectedValues);
- $this->resetCachedSelections();
- }
- else if($this->_cachedSelectedIndices!==null)
- {
- $this->setSelectedIndices($this->_cachedSelectedIndices);
- $this->resetCachedSelections();
- }
- }
-
- private function resetCachedSelections()
- {
- $this->_cachedSelectedValue=null;
- $this->_cachedSelectedIndex=-1;
- $this->_cachedSelectedValues=null;
- $this->_cachedSelectedIndices=null;
- }
-
- /**
- * Creates a collection object to hold list items.
- * This method may be overriden to create a customized collection.
- * @return TListItemCollection the collection object
- */
- protected function createListItemCollection()
- {
- return new TListItemCollection;
- }
-
- /**
- * Saves items into viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('Items',$this->_items->saveState(),null);
- else
- $this->clearViewState('Items');
- }
-
- /**
- * Loads items from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- $this->_stateLoaded=true;
- if(!$this->getIsDataBound())
- {
- $this->_items=$this->createListItemCollection();
- $this->_items->loadState($this->getViewState('Items',null));
- }
- $this->clearViewState('Items');
- }
-
- /**
- * @return boolean whether this is a multiselect control. Defaults to false.
- */
- protected function getIsMultiSelect()
- {
- return false;
- }
-
- /**
- * @return boolean whether performing databind should append items or clear the existing ones. Defaults to false.
- */
- public function getAppendDataBoundItems()
- {
- return $this->getViewState('AppendDataBoundItems',false);
- }
-
- /**
- * @param boolean whether performing databind should append items or clear the existing ones.
- */
- public function setAppendDataBoundItems($value)
- {
- $this->setViewState('AppendDataBoundItems',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user makes change to the list control and then tabs out of it.
- * Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * makes change to the list control and then tabs out of it.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event trigger by this list control will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this list control will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return string the field of the data source that provides the text content of the list items.
- */
- public function getDataTextField()
- {
- return $this->getViewState('DataTextField','');
- }
-
- /**
- * @param string the field of the data source that provides the text content of the list items.
- */
- public function setDataTextField($value)
- {
- $this->setViewState('DataTextField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how data bound to the list control is displayed.
- */
- public function getDataTextFormatString()
- {
- return $this->getViewState('DataTextFormatString','');
- }
-
- /**
- * Sets data text format string.
- * The format string is used in {@link TDataValueFormatter::format()} to format the Text property value
- * of each item in the list control.
- * @param string the formatting string used to control how data bound to the list control is displayed.
- * @see TDataValueFormatter::format()
- */
- public function setDataTextFormatString($value)
- {
- $this->setViewState('DataTextFormatString',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the value of each list item.
- */
- public function getDataValueField()
- {
- return $this->getViewState('DataValueField','');
- }
-
- /**
- * @param string the field of the data source that provides the value of each list item.
- */
- public function setDataValueField($value)
- {
- $this->setViewState('DataValueField',$value,'');
- }
-
- /**
- * @return string the field of the data source that provides the label of the list item groups
- */
- public function getDataGroupField()
- {
- return $this->getViewState('DataGroupField','');
- }
-
- /**
- * @param string the field of the data source that provides the label of the list item groups
- */
- public function setDataGroupField($value)
- {
- $this->setViewState('DataGroupField',$value,'');
- }
-
- /**
- * @return integer the number of items in the list control
- */
- public function getItemCount()
- {
- return $this->_items?$this->_items->getCount():0;
- }
-
- /**
- * @return boolean whether the list control contains any items.
- */
- public function getHasItems()
- {
- return ($this->_items && $this->_items->getCount()>0);
- }
-
- /**
- * @return TListItemCollection the item collection
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=$this->createListItemCollection();
- return $this->_items;
- }
-
- /**
- * @return integer the index (zero-based) of the item being selected, -1 if no item is selected.
- */
- public function getSelectedIndex()
- {
- if($this->_items)
- {
- $n=$this->_items->getCount();
- for($i=0;$i<$n;++$i)
- if($this->_items->itemAt($i)->getSelected())
- return $i;
- }
- return -1;
- }
-
- /**
- * @param integer the index (zero-based) of the item to be selected
- */
- public function setSelectedIndex($index)
- {
- if(($index=TPropertyValue::ensureInteger($index))<0)
- $index=-1;
- if($this->_items)
- {
- $this->clearSelection();
- if($index>=0 && $index<$this->_items->getCount())
- $this->_items->itemAt($index)->setSelected(true);
- }
- $this->_cachedSelectedIndex=$index;
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedIndex($index);
- }
-
- /**
- * @return array list of index of items that are selected
- */
- public function getSelectedIndices()
- {
- $selections=array();
- if($this->_items)
- {
- $n=$this->_items->getCount();
- for($i=0;$i<$n;++$i)
- if($this->_items->itemAt($i)->getSelected())
- $selections[]=$i;
- }
- return $selections;
- }
-
- /**
- * @param array list of index of items to be selected
- */
- public function setSelectedIndices($indices)
- {
- if($this->getIsMultiSelect())
- {
- if($this->_items)
- {
- $this->clearSelection();
- $n=$this->_items->getCount();
- foreach($indices as $index)
- {
- if($index>=0 && $index<$n)
- $this->_items->itemAt($index)->setSelected(true);
- }
- }
- $this->_cachedSelectedIndices=$indices;
- }
- else
- throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedIndices($indices);
- }
-
- /**
- * @return TListItem|null the selected item with the lowest cardinal index, null if no item is selected.
- */
- public function getSelectedItem()
- {
- if(($index=$this->getSelectedIndex())>=0)
- return $this->_items->itemAt($index);
- else
- return null;
- }
-
- /**
- * Returns the value of the selected item with the lowest cardinal index.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getSelectedValue()}.
- * @return string the value of the selected item with the lowest cardinal index, empty if no selection.
- * @see getSelectedValue
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * Selects an item by the specified value.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setSelectedValue()}.
- * @param string the value of the item to be selected.
- * @see setSelectedValue
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setSelectedValue($value);
- }
-
- /**
- * @return string the value of the selected item with the lowest cardinal index, empty if no selection
- */
- public function getSelectedValue()
- {
- $index=$this->getSelectedIndex();
- return $index>=0?$this->getItems()->itemAt($index)->getValue():'';
- }
-
- /**
- * Sets selection by item value.
- * Existing selections will be cleared if the item value is found in the item collection.
- * Note, if the value is null, existing selections will also be cleared.
- * @param string the value of the item to be selected.
- */
- public function setSelectedValue($value)
- {
- if($this->_items)
- {
- if($value===null)
- $this->clearSelection();
- else if(($item=$this->_items->findItemByValue($value))!==null)
- {
- $this->clearSelection();
- $item->setSelected(true);
- }
- else
- $this->clearSelection();
- }
- $this->_cachedSelectedValue=$value;
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedValue($value);
- }
-
-
- /**
- * @return array list of the selected item values (strings)
- */
- public function getSelectedValues()
- {
- $values=array();
- if($this->_items)
- {
- foreach($this->_items as $item)
- {
- if($item->getSelected())
- $values[]=$item->getValue();
- }
- }
- return $values;
- }
-
- /**
- * @param array list of the selected item values
- */
- public function setSelectedValues($values)
- {
- if($this->getIsMultiSelect())
- {
- if($this->_items)
- {
- $this->clearSelection();
- $lookup=array();
- foreach($this->_items as $item)
- $lookup[$item->getValue()]=$item;
- foreach($values as $value)
- {
- if(isset($lookup["$value"]))
- $lookup["$value"]->setSelected(true);
- }
- }
- $this->_cachedSelectedValues=$values;
- }
- else
- throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->setSelectedValues($values);
- }
-
- /**
- * @return string selected value
- */
- public function getText()
- {
- return $this->getSelectedValue();
- }
-
- /**
- * @param string value to be selected
- */
- public function setText($value)
- {
- $this->setSelectedValue($value);
- }
-
- /**
- * Clears all existing selections.
- */
- public function clearSelection()
- {
- if($this->_items)
- {
- foreach($this->_items as $item)
- $item->setSelected(false);
- }
-
- if($this->getAdapter() instanceof IListControlAdapter)
- $this->getAdapter()->clearSelection();
- }
-
- /**
- * @return string the group of validators which the list control causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the list control causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return string the prompt text which is to be displayed as the first list item.
- * @since 3.1.1
- */
- public function getPromptText()
- {
- return $this->getViewState('PromptText','');
- }
-
- /**
- * @param string the prompt text which is to be displayed as the first list item.
- * @since 3.1.1
- */
- public function setPromptText($value)
- {
- $this->setViewState('PromptText',$value,'');
- }
-
- /**
- * @return string the prompt selection value.
- * @see getPromptText
- * @since 3.1.1
- */
- public function getPromptValue()
- {
- return $this->getViewState('PromptValue','');
- }
-
- /**
- * @param string the prompt selection value. If empty, {@link getPromptText PromptText} will be used as the value.
- * @see setPromptText
- * @since 3.1.1
- */
- public function setPromptValue($value)
- {
- $this->setViewState('PromptValue',(string)$value,'');
- }
-
- /**
- * Raises OnSelectedIndexChanged event when selection is changed.
- * This method is invoked when the list control has its selection changed
- * by end-users.
- * @param TEventParameter event parameter
- */
- public function onSelectedIndexChanged($param)
- {
- $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
- $this->onTextChanged($param);
- }
-
- /**
- * Raises OnTextChanged event when selection is changed.
- * This method is invoked when the list control has its selection changed
- * by end-users.
- * @param TEventParameter event parameter
- */
- public function onTextChanged($param)
- {
- $this->raiseEvent('OnTextChanged',$this,$param);
- }
-
- /**
- * Renders the prompt text, if any.
- * @param THtmlWriter writer
- * @since 3.1.1
- */
- protected function renderPrompt($writer)
- {
- $text=$this->getPromptText();
- $value=$this->getPromptValue();
- if($value==='')
- $value=$text;
- if($value!=='')
- {
- $writer->addAttribute('value',$value);
- $writer->renderBeginTag('option');
- $writer->write(THttpUtility::htmlEncode($text));
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
-
- /**
- * Renders body content of the list control.
- * This method renders items contained in the list control as the body content.
- * @param THtmlWriter writer
- */
- public function renderContents($writer)
- {
- $this->renderPrompt($writer);
-
- if($this->_items)
- {
- $writer->writeLine();
- $previousGroup=null;
- foreach($this->_items as $item)
- {
- if($item->getEnabled())
- {
- if($item->getHasAttributes())
- {
- $group=$item->getAttributes()->remove('Group');
- if($group!==$previousGroup)
- {
- if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $previousGroup=null;
- }
- if($group!==null)
- {
- $writer->addAttribute('label',$group);
- $writer->renderBeginTag('optgroup');
- $writer->writeLine();
- $previousGroup=$group;
- }
- }
- foreach($item->getAttributes() as $name=>$value)
- $writer->addAttribute($name,$value);
- }
- else if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $previousGroup=null;
- }
- if($item->getSelected())
- $writer->addAttribute('selected','selected');
- $writer->addAttribute('value',$item->getValue());
- $writer->renderBeginTag('option');
- $writer->write(THttpUtility::htmlEncode($item->getText()));
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
- if($previousGroup!==null)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- }
- }
- }
-
- /**
- * Formats the text value according to a format string.
- * If the format string is empty, the original value is converted into
- * a string and returned.
- * If the format string starts with '#', the string is treated as a PHP expression
- * within which the token '{0}' is translated with the data value to be formated.
- * Otherwise, the format string and the data value are passed
- * as the first and second parameters in {@link sprintf}.
- * @param string format string
- * @param mixed the data to be formatted
- * @return string the formatted result
- */
- protected function formatDataValue($formatString,$value)
- {
- if($formatString==='')
- return TPropertyValue::ensureString($value);
- else if($formatString[0]==='#')
- {
- $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
- try
- {
- if(eval("\$result=$expression;")===false)
- throw new Exception('');
- return $result;
- }
- catch(Exception $e)
- {
- throw new TInvalidDataValueException('listcontrol_expression_invalid',get_class($this),$expression,$e->getMessage());
- }
- }
- else
- return sprintf($formatString,$value);
- }
-}
-
-/**
- * IListControlAdapter interface
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Revision: $ Sun Jun 25 04:53:43 EST 2006 $
- * @package System.Web.UI.ActiveControls
- * @since 3.0
- */
-interface IListControlAdapter
-{
- /**
- * Selects an item based on zero-base index on the client side.
- * @param integer the index (zero-based) of the item to be selected
- */
- public function setSelectedIndex($index);
- /**
- * Selects a list of item based on zero-base indices on the client side.
- * @param array list of index of items to be selected
- */
- public function setSelectedIndices($indices);
-
- /**
- * Sets selection by item value on the client side.
- * @param string the value of the item to be selected.
- */
- public function setSelectedValue($value);
-
- /**
- * Sets selection by a list of item values on the client side.
- * @param array list of the selected item values
- */
- public function setSelectedValues($values);
-
- /**
- * Clears all existing selections on the client side.
- */
- public function clearSelection();
-}
-
-
-?>
+<?php
+
+/**
+ * TListControl class file
+ *
+ * @author Robin J. Rogge <rojaro@gmail.com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes the supporting classes
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Web.UI.WebControls.TListItem');
+Prado::using('System.Collections.TListItemCollection');
+Prado::using('System.Collections.TAttributeCollection');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TListControl class
+ *
+ * TListControl is a base class for list controls, such as {@link TListBox},
+ * {@link TDropDownList}, {@link TCheckBoxList}, etc.
+ * It manages the items and their status in a list control.
+ * It also implements how the items can be populated from template and
+ * data source.
+ *
+ * The property {@link getItems} returns a list of the items in the control.
+ * To specify or determine which item is selected, use the
+ * {@link getSelectedIndex SelectedIndex} property that indicates the zero-based
+ * index of the selected item in the item list. You may also use
+ * {@link getSelectedItem SelectedItem} and {@link getSelectedValue SelectedValue}
+ * to get the selected item and its value. For multiple selection lists
+ * (such as {@link TCheckBoxList} and {@link TListBox}), property
+ * {@link getSelectedIndices SelectedIndices} is useful.
+ *
+ * TListControl implements {@link setAutoPostBack AutoPostBack} which allows
+ * a list control to postback the page if the selections of the list items are changed.
+ * The {@link setCausesValidation CausesValidation} and {@link setValidationGroup ValidationGroup}
+ * properties may be used to specify that validation be performed when auto postback occurs.
+ *
+ * There are three ways to populate the items in a list control: from template,
+ * using {@link setDataSource DataSource} and using {@link setDataSourceID DataSourceID}.
+ * The latter two are covered in {@link TDataBoundControl}. To specify items via
+ * template, using the following template syntax:
+ * <code>
+ * <com:TListControl>
+ * <com:TListItem Value="xxx" Text="yyy" >
+ * <com:TListItem Value="xxx" Text="yyy" Selected="true" >
+ * <com:TListItem Value="xxx" Text="yyy" >
+ * </com:TListControl>
+ * </code>
+ *
+ * When {@link setDataSource DataSource} or {@link setDataSourceID DataSourceID}
+ * is used to populate list items, the {@link setDataTextField DataTextField} and
+ * {@link setDataValueField DataValueField} properties are used to specify which
+ * columns of the data will be used to populate the text and value of the items.
+ * For example, if a data source is as follows,
+ * <code>
+ * $dataSource=array(
+ * array('name'=>'John', 'age'=>31),
+ * array('name'=>'Cary', 'age'=>28),
+ * array('name'=>'Rose', 'age'=>35),
+ * );
+ * </code>
+ * setting {@link setDataTextField DataTextField} and {@link setDataValueField DataValueField}
+ * to 'name' and 'age' will make the first item's text be 'John', value be 31,
+ * the second item's text be 'Cary', value be 28, and so on.
+ * The {@link setDataTextFormatString DataTextFormatString} property may be further
+ * used to format how the item should be displayed. See {@link formatDataValue()}
+ * for an explanation of the format string.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+abstract class TListControl extends TDataBoundControl implements IDataRenderer
+{
+ /**
+ * @var TListItemCollection item list
+ */
+ private $_items=null;
+ /**
+ * @var boolean whether items are restored from viewstate
+ */
+ private $_stateLoaded=false;
+ /**
+ * @var mixed the following selection variables are used
+ * to keep selections when Items are not available
+ */
+ private $_cachedSelectedIndex=-1;
+ private $_cachedSelectedValue=null;
+ private $_cachedSelectedIndices=null;
+ private $_cachedSelectedValues=null;
+
+ /**
+ * @return string tag name of the list control
+ */
+ protected function getTagName()
+ {
+ return 'select';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ if($this->getIsMultiSelect())
+ $writer->addAttribute('multiple','multiple');
+ if($this->getEnabled(true))
+ {
+ if($this->getAutoPostBack()
+ && $this->getEnableClientScript()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ }
+ else if($this->getEnabled())
+ $writer->addAttribute('disabled','disabled');
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the javascript for list control.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * Derived classes may override this method and return customized js class names.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListControl';
+ }
+
+ /**
+ * @return array postback options for JS postback code
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['EventTarget'] = $this->getUniqueID();
+ return $options;
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TListItem} objects into the {@link getItems Items} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ // Do not add items from template if items are loaded from viewstate
+ if(!$this->_stateLoaded && ($object instanceof TListItem))
+ {
+ $index=$this->getItems()->add($object);
+ if(($this->_cachedSelectedValue!==null && $this->_cachedSelectedValue===$object->getValue()) || ($this->_cachedSelectedIndex===$index))
+ {
+ $object->setSelected(true);
+ $this->_cachedSelectedValue=null;
+ $this->_cachedSelectedIndex=-1;
+ }
+ }
+ }
+
+ /**
+ * Performs databinding to populate list items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $items=$this->getItems();
+ if(!$this->getAppendDataBoundItems())
+ $items->clear();
+ $textField=$this->getDataTextField();
+ if($textField==='')
+ $textField=0;
+ $valueField=$this->getDataValueField();
+ if($valueField==='')
+ $valueField=1;
+ $textFormat=$this->getDataTextFormatString();
+ $groupField=$this->getDataGroupField();
+ foreach($data as $key=>$object)
+ {
+ $item=$items->createListItem();
+ if(is_array($object) || is_object($object))
+ {
+ $text=TDataFieldAccessor::getDataFieldValue($object,$textField);
+ $value=TDataFieldAccessor::getDataFieldValue($object,$valueField);
+ $item->setValue($value);
+ if($groupField!=='')
+ $item->setAttribute('Group',TDataFieldAccessor::getDataFieldValue($object,$groupField));
+ }
+ else
+ {
+ $text=$object;
+ $item->setValue("$key");
+ }
+ $item->setText($this->formatDataValue($textFormat,$text));
+ }
+ // SelectedValue or SelectedIndex may be set before databinding
+ // so we make them be effective now
+ if($this->_cachedSelectedValue!==null)
+ {
+ $this->setSelectedValue($this->_cachedSelectedValue);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedIndex!==-1)
+ {
+ $this->setSelectedIndex($this->_cachedSelectedIndex);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedValues!==null)
+ {
+ $this->setSelectedValues($this->_cachedSelectedValues);
+ $this->resetCachedSelections();
+ }
+ else if($this->_cachedSelectedIndices!==null)
+ {
+ $this->setSelectedIndices($this->_cachedSelectedIndices);
+ $this->resetCachedSelections();
+ }
+ }
+
+ private function resetCachedSelections()
+ {
+ $this->_cachedSelectedValue=null;
+ $this->_cachedSelectedIndex=-1;
+ $this->_cachedSelectedValues=null;
+ $this->_cachedSelectedIndices=null;
+ }
+
+ /**
+ * Creates a collection object to hold list items.
+ * This method may be overriden to create a customized collection.
+ * @return TListItemCollection the collection object
+ */
+ protected function createListItemCollection()
+ {
+ return new TListItemCollection;
+ }
+
+ /**
+ * Saves items into viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('Items',$this->_items->saveState(),null);
+ else
+ $this->clearViewState('Items');
+ }
+
+ /**
+ * Loads items from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ $this->_stateLoaded=true;
+ if(!$this->getIsDataBound())
+ {
+ $this->_items=$this->createListItemCollection();
+ $this->_items->loadState($this->getViewState('Items',null));
+ }
+ $this->clearViewState('Items');
+ }
+
+ /**
+ * @return boolean whether this is a multiselect control. Defaults to false.
+ */
+ protected function getIsMultiSelect()
+ {
+ return false;
+ }
+
+ /**
+ * @return boolean whether performing databind should append items or clear the existing ones. Defaults to false.
+ */
+ public function getAppendDataBoundItems()
+ {
+ return $this->getViewState('AppendDataBoundItems',false);
+ }
+
+ /**
+ * @param boolean whether performing databind should append items or clear the existing ones.
+ */
+ public function setAppendDataBoundItems($value)
+ {
+ $this->setViewState('AppendDataBoundItems',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user makes change to the list control and then tabs out of it.
+ * Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * makes change to the list control and then tabs out of it.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this list control will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this list control will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return string the field of the data source that provides the text content of the list items.
+ */
+ public function getDataTextField()
+ {
+ return $this->getViewState('DataTextField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the text content of the list items.
+ */
+ public function setDataTextField($value)
+ {
+ $this->setViewState('DataTextField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how data bound to the list control is displayed.
+ */
+ public function getDataTextFormatString()
+ {
+ return $this->getViewState('DataTextFormatString','');
+ }
+
+ /**
+ * Sets data text format string.
+ * The format string is used in {@link TDataValueFormatter::format()} to format the Text property value
+ * of each item in the list control.
+ * @param string the formatting string used to control how data bound to the list control is displayed.
+ * @see TDataValueFormatter::format()
+ */
+ public function setDataTextFormatString($value)
+ {
+ $this->setViewState('DataTextFormatString',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the value of each list item.
+ */
+ public function getDataValueField()
+ {
+ return $this->getViewState('DataValueField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the value of each list item.
+ */
+ public function setDataValueField($value)
+ {
+ $this->setViewState('DataValueField',$value,'');
+ }
+
+ /**
+ * @return string the field of the data source that provides the label of the list item groups
+ */
+ public function getDataGroupField()
+ {
+ return $this->getViewState('DataGroupField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the label of the list item groups
+ */
+ public function setDataGroupField($value)
+ {
+ $this->setViewState('DataGroupField',$value,'');
+ }
+
+ /**
+ * @return integer the number of items in the list control
+ */
+ public function getItemCount()
+ {
+ return $this->_items?$this->_items->getCount():0;
+ }
+
+ /**
+ * @return boolean whether the list control contains any items.
+ */
+ public function getHasItems()
+ {
+ return ($this->_items && $this->_items->getCount()>0);
+ }
+
+ /**
+ * @return TListItemCollection the item collection
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=$this->createListItemCollection();
+ return $this->_items;
+ }
+
+ /**
+ * @return integer the index (zero-based) of the item being selected, -1 if no item is selected.
+ */
+ public function getSelectedIndex()
+ {
+ if($this->_items)
+ {
+ $n=$this->_items->getCount();
+ for($i=0;$i<$n;++$i)
+ if($this->_items->itemAt($i)->getSelected())
+ return $i;
+ }
+ return -1;
+ }
+
+ /**
+ * @param integer the index (zero-based) of the item to be selected
+ */
+ public function setSelectedIndex($index)
+ {
+ if(($index=TPropertyValue::ensureInteger($index))<0)
+ $index=-1;
+ if($this->_items)
+ {
+ $this->clearSelection();
+ if($index>=0 && $index<$this->_items->getCount())
+ $this->_items->itemAt($index)->setSelected(true);
+ }
+ $this->_cachedSelectedIndex=$index;
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedIndex($index);
+ }
+
+ /**
+ * @return array list of index of items that are selected
+ */
+ public function getSelectedIndices()
+ {
+ $selections=array();
+ if($this->_items)
+ {
+ $n=$this->_items->getCount();
+ for($i=0;$i<$n;++$i)
+ if($this->_items->itemAt($i)->getSelected())
+ $selections[]=$i;
+ }
+ return $selections;
+ }
+
+ /**
+ * @param array list of index of items to be selected
+ */
+ public function setSelectedIndices($indices)
+ {
+ if($this->getIsMultiSelect())
+ {
+ if($this->_items)
+ {
+ $this->clearSelection();
+ $n=$this->_items->getCount();
+ foreach($indices as $index)
+ {
+ if($index>=0 && $index<$n)
+ $this->_items->itemAt($index)->setSelected(true);
+ }
+ }
+ $this->_cachedSelectedIndices=$indices;
+ }
+ else
+ throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedIndices($indices);
+ }
+
+ /**
+ * @return TListItem|null the selected item with the lowest cardinal index, null if no item is selected.
+ */
+ public function getSelectedItem()
+ {
+ if(($index=$this->getSelectedIndex())>=0)
+ return $this->_items->itemAt($index);
+ else
+ return null;
+ }
+
+ /**
+ * Returns the value of the selected item with the lowest cardinal index.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getSelectedValue()}.
+ * @return string the value of the selected item with the lowest cardinal index, empty if no selection.
+ * @see getSelectedValue
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * Selects an item by the specified value.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setSelectedValue()}.
+ * @param string the value of the item to be selected.
+ * @see setSelectedValue
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setSelectedValue($value);
+ }
+
+ /**
+ * @return string the value of the selected item with the lowest cardinal index, empty if no selection
+ */
+ public function getSelectedValue()
+ {
+ $index=$this->getSelectedIndex();
+ return $index>=0?$this->getItems()->itemAt($index)->getValue():'';
+ }
+
+ /**
+ * Sets selection by item value.
+ * Existing selections will be cleared if the item value is found in the item collection.
+ * Note, if the value is null, existing selections will also be cleared.
+ * @param string the value of the item to be selected.
+ */
+ public function setSelectedValue($value)
+ {
+ if($this->_items)
+ {
+ if($value===null)
+ $this->clearSelection();
+ else if(($item=$this->_items->findItemByValue($value))!==null)
+ {
+ $this->clearSelection();
+ $item->setSelected(true);
+ }
+ else
+ $this->clearSelection();
+ }
+ $this->_cachedSelectedValue=$value;
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedValue($value);
+ }
+
+
+ /**
+ * @return array list of the selected item values (strings)
+ */
+ public function getSelectedValues()
+ {
+ $values=array();
+ if($this->_items)
+ {
+ foreach($this->_items as $item)
+ {
+ if($item->getSelected())
+ $values[]=$item->getValue();
+ }
+ }
+ return $values;
+ }
+
+ /**
+ * @param array list of the selected item values
+ */
+ public function setSelectedValues($values)
+ {
+ if($this->getIsMultiSelect())
+ {
+ if($this->_items)
+ {
+ $this->clearSelection();
+ $lookup=array();
+ foreach($this->_items as $item)
+ $lookup[$item->getValue()]=$item;
+ foreach($values as $value)
+ {
+ if(isset($lookup["$value"]))
+ $lookup["$value"]->setSelected(true);
+ }
+ }
+ $this->_cachedSelectedValues=$values;
+ }
+ else
+ throw new TNotSupportedException('listcontrol_multiselect_unsupported',get_class($this));
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->setSelectedValues($values);
+ }
+
+ /**
+ * @return string selected value
+ */
+ public function getText()
+ {
+ return $this->getSelectedValue();
+ }
+
+ /**
+ * @param string value to be selected
+ */
+ public function setText($value)
+ {
+ $this->setSelectedValue($value);
+ }
+
+ /**
+ * Clears all existing selections.
+ */
+ public function clearSelection()
+ {
+ if($this->_items)
+ {
+ foreach($this->_items as $item)
+ $item->setSelected(false);
+ }
+
+ if($this->getAdapter() instanceof IListControlAdapter)
+ $this->getAdapter()->clearSelection();
+ }
+
+ /**
+ * @return string the group of validators which the list control causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the list control causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return string the prompt text which is to be displayed as the first list item.
+ * @since 3.1.1
+ */
+ public function getPromptText()
+ {
+ return $this->getViewState('PromptText','');
+ }
+
+ /**
+ * @param string the prompt text which is to be displayed as the first list item.
+ * @since 3.1.1
+ */
+ public function setPromptText($value)
+ {
+ $this->setViewState('PromptText',$value,'');
+ }
+
+ /**
+ * @return string the prompt selection value.
+ * @see getPromptText
+ * @since 3.1.1
+ */
+ public function getPromptValue()
+ {
+ return $this->getViewState('PromptValue','');
+ }
+
+ /**
+ * @param string the prompt selection value. If empty, {@link getPromptText PromptText} will be used as the value.
+ * @see setPromptText
+ * @since 3.1.1
+ */
+ public function setPromptValue($value)
+ {
+ $this->setViewState('PromptValue',(string)$value,'');
+ }
+
+ /**
+ * Raises OnSelectedIndexChanged event when selection is changed.
+ * This method is invoked when the list control has its selection changed
+ * by end-users.
+ * @param TEventParameter event parameter
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $this->raiseEvent('OnSelectedIndexChanged',$this,$param);
+ $this->onTextChanged($param);
+ }
+
+ /**
+ * Raises OnTextChanged event when selection is changed.
+ * This method is invoked when the list control has its selection changed
+ * by end-users.
+ * @param TEventParameter event parameter
+ */
+ public function onTextChanged($param)
+ {
+ $this->raiseEvent('OnTextChanged',$this,$param);
+ }
+
+ /**
+ * Renders the prompt text, if any.
+ * @param THtmlWriter writer
+ * @since 3.1.1
+ */
+ protected function renderPrompt($writer)
+ {
+ $text=$this->getPromptText();
+ $value=$this->getPromptValue();
+ if($value==='')
+ $value=$text;
+ if($value!=='')
+ {
+ $writer->addAttribute('value',$value);
+ $writer->renderBeginTag('option');
+ $writer->write(THttpUtility::htmlEncode($text));
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+
+ /**
+ * Renders body content of the list control.
+ * This method renders items contained in the list control as the body content.
+ * @param THtmlWriter writer
+ */
+ public function renderContents($writer)
+ {
+ $this->renderPrompt($writer);
+
+ if($this->_items)
+ {
+ $writer->writeLine();
+ $previousGroup=null;
+ foreach($this->_items as $item)
+ {
+ if($item->getEnabled())
+ {
+ if($item->getHasAttributes())
+ {
+ $group=$item->getAttributes()->remove('Group');
+ if($group!==$previousGroup)
+ {
+ if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $previousGroup=null;
+ }
+ if($group!==null)
+ {
+ $writer->addAttribute('label',$group);
+ $writer->renderBeginTag('optgroup');
+ $writer->writeLine();
+ $previousGroup=$group;
+ }
+ }
+ foreach($item->getAttributes() as $name=>$value)
+ $writer->addAttribute($name,$value);
+ }
+ else if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $previousGroup=null;
+ }
+ if($item->getSelected())
+ $writer->addAttribute('selected','selected');
+ $writer->addAttribute('value',$item->getValue());
+ $writer->renderBeginTag('option');
+ $writer->write(THttpUtility::htmlEncode($item->getText()));
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+ if($previousGroup!==null)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ }
+ }
+
+ /**
+ * Formats the text value according to a format string.
+ * If the format string is empty, the original value is converted into
+ * a string and returned.
+ * If the format string starts with '#', the string is treated as a PHP expression
+ * within which the token '{0}' is translated with the data value to be formated.
+ * Otherwise, the format string and the data value are passed
+ * as the first and second parameters in {@link sprintf}.
+ * @param string format string
+ * @param mixed the data to be formatted
+ * @return string the formatted result
+ */
+ protected function formatDataValue($formatString,$value)
+ {
+ if($formatString==='')
+ return TPropertyValue::ensureString($value);
+ else if($formatString[0]==='#')
+ {
+ $expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
+ try
+ {
+ if(eval("\$result=$expression;")===false)
+ throw new Exception('');
+ return $result;
+ }
+ catch(Exception $e)
+ {
+ throw new TInvalidDataValueException('listcontrol_expression_invalid',get_class($this),$expression,$e->getMessage());
+ }
+ }
+ else
+ return sprintf($formatString,$value);
+ }
+}
+
+/**
+ * IListControlAdapter interface
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ Sun Jun 25 04:53:43 EST 2006 $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.0
+ */
+interface IListControlAdapter
+{
+ /**
+ * Selects an item based on zero-base index on the client side.
+ * @param integer the index (zero-based) of the item to be selected
+ */
+ public function setSelectedIndex($index);
+ /**
+ * Selects a list of item based on zero-base indices on the client side.
+ * @param array list of index of items to be selected
+ */
+ public function setSelectedIndices($indices);
+
+ /**
+ * Sets selection by item value on the client side.
+ * @param string the value of the item to be selected.
+ */
+ public function setSelectedValue($value);
+
+ /**
+ * Sets selection by a list of item values on the client side.
+ * @param array list of the selected item values
+ */
+ public function setSelectedValues($values);
+
+ /**
+ * Clears all existing selections on the client side.
+ */
+ public function clearSelection();
+}
+
+
+?>
diff --git a/framework/Web/UI/WebControls/TListControlValidator.php b/framework/Web/UI/WebControls/TListControlValidator.php
index a5be67b3..75a0510c 100644
--- a/framework/Web/UI/WebControls/TListControlValidator.php
+++ b/framework/Web/UI/WebControls/TListControlValidator.php
@@ -1,225 +1,225 @@
-<?php
-/**
- * TListControlValidator class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TListControlValidator class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TListControlValidator class.
- *
- * TListControlValidator checks the number of selection and their values
- * for a <b>TListControl that allows multiple selection</b>.
- *
- * You can specify the minimum or maximum (or both) number of selections
- * required using the {@link setMinSelection MinSelection} and
- * {@link setMaxSelection MaxSelection} properties, respectively. In addition,
- * you can specify a comma separated list of required selected values via the
- * {@link setRequiredSelections RequiredSelections} property.
- *
- * Examples
- * - At least two selections
- * <code>
- * <com:TListBox ID="listbox" SelectionMode="Multiple">
- * <com:TListItem Text="item1" Value="value1" />
- * <com:TListItem Text="item2" Value="value2" />
- * <com:TListItem Text="item3" Value="value3" />
- * </com:TListBox>
- *
- * <com:TListControlValidator
- * ControlToValidate="listbox"
- * MinSelection="2"
- * ErrorMessage="Please select at least 2" />
- * </code>
- * - "value1" must be selected <b>and</b> at least 1 other
- * <code>
- * <com:TCheckBoxList ID="checkboxes">
- * <com:TListItem Text="item1" Value="value1" />
- * <com:TListItem Text="item2" Value="value2" />
- * <com:TListItem Text="item3" Value="value3" />
- * </com:TCheckBoxList>
- *
- * <com:TListControlValidator
- * ControlToValidate="checkboxes"
- * RequiredSelections="value1"
- * MinSelection="2"
- * ErrorMessage="Please select 'item1' and at least 1 other" />
- * </code>
- *
- * @author Xiang Wei Zhuo <weizhuo[at]gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListControlValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TListControlValidator';
- }
-
- /**
- * @return integer min number of selections. Defaults to -1, meaning not set.
- */
- public function getMinSelection()
- {
- return $this->getViewState('MinSelection',-1);
- }
-
- /**
- * @param integer minimum number of selections.
- */
- public function setMinSelection($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- $this->setViewState('MinSelection',$value,-1);
- }
-
- /**
- * @return integer max number of selections. Defaults to -1, meaning not set.
- */
- public function getMaxSelection()
- {
- return $this->getViewState('MaxSelection',-1);
- }
-
- /**
- * @param integer max number of selections.
- */
- public function setMaxSelection($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- $value=-1;
- $this->setViewState('MaxSelection',$value,-1);
- }
-
- /**
- * Get a comma separated list of required selected values.
- * @return string comma separated list of required values.
- */
- public function getRequiredSelections()
- {
- return $this->getViewState('RequiredSelections','');
- }
-
- /**
- * Set the list of required values, using aa comma separated list.
- * @param string comma separated list of required values.
- */
- public function setRequiredSelections($value)
- {
- $this->setViewState('RequiredSelections',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input component changes its data
- * from the InitialValue or the input component is not given.
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $control=$this->getValidationTarget();
-
- $exists = true;
- $values = $this->getSelection($control);
- $count = count($values);
- $required = $this->getRequiredValues();
-
- //if required, check the values
- if(!empty($required))
- {
- if($count < count($required) )
- return false;
- foreach($required as $require)
- $exists = $exists && in_array($require, $values);
- }
-
- $min = $this->getMinSelection();
- $max = $this->getMaxSelection();
-
- if($min !== -1 && $max !== -1)
- return $exists && $count >= $min && $count <= $max;
- else if($min === -1 && $max !== -1)
- return $exists && $count <= $max;
- else if($min !== -1 && $max === -1)
- return $exists && $count >= $min;
- else
- return $exists;
- }
-
- /**
- * @param TListControl control to validate
- * @return array number of selected values and its values.
- */
- protected function getSelection($control)
- {
- $values = array();
-
- //get the data
- foreach($control->getItems() as $item)
- {
- if($item->getSelected())
- $values[] = $item->getValue();
- }
- return $values;
- }
-
- /**
- * @return array list of required values.
- */
- protected function getRequiredValues()
- {
- $required = array();
- $string = $this->getRequiredSelections();
- if(!empty($string))
- $required = preg_split('/,\s*/', $string);
- return $required;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $control = $this->getValidationTarget();
-
- if(!$control instanceof TListControl)
- {
- throw new TConfigurationException(
- 'listcontrolvalidator_invalid_control',
- $this->getID(),$this->getControlToValidate(), get_class($control));
- }
-
- $min = $this->getMinSelection();
- $max = $this->getMaxSelection();
- if($min !== -1)
- $options['Min']= $min;
- if($max !== -1)
- $options['Max']= $max;
- $required = $this->getRequiredSelections();
- if(strlen($required) > 0)
- $options['Required']= $required;
- $options['TotalItems'] = $control->getItemCount();
-
- return $options;
- }
-}
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TListControlValidator class.
+ *
+ * TListControlValidator checks the number of selection and their values
+ * for a <b>TListControl that allows multiple selection</b>.
+ *
+ * You can specify the minimum or maximum (or both) number of selections
+ * required using the {@link setMinSelection MinSelection} and
+ * {@link setMaxSelection MaxSelection} properties, respectively. In addition,
+ * you can specify a comma separated list of required selected values via the
+ * {@link setRequiredSelections RequiredSelections} property.
+ *
+ * Examples
+ * - At least two selections
+ * <code>
+ * <com:TListBox ID="listbox" SelectionMode="Multiple">
+ * <com:TListItem Text="item1" Value="value1" />
+ * <com:TListItem Text="item2" Value="value2" />
+ * <com:TListItem Text="item3" Value="value3" />
+ * </com:TListBox>
+ *
+ * <com:TListControlValidator
+ * ControlToValidate="listbox"
+ * MinSelection="2"
+ * ErrorMessage="Please select at least 2" />
+ * </code>
+ * - "value1" must be selected <b>and</b> at least 1 other
+ * <code>
+ * <com:TCheckBoxList ID="checkboxes">
+ * <com:TListItem Text="item1" Value="value1" />
+ * <com:TListItem Text="item2" Value="value2" />
+ * <com:TListItem Text="item3" Value="value3" />
+ * </com:TCheckBoxList>
+ *
+ * <com:TListControlValidator
+ * ControlToValidate="checkboxes"
+ * RequiredSelections="value1"
+ * MinSelection="2"
+ * ErrorMessage="Please select 'item1' and at least 1 other" />
+ * </code>
+ *
+ * @author Xiang Wei Zhuo <weizhuo[at]gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListControlValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TListControlValidator';
+ }
+
+ /**
+ * @return integer min number of selections. Defaults to -1, meaning not set.
+ */
+ public function getMinSelection()
+ {
+ return $this->getViewState('MinSelection',-1);
+ }
+
+ /**
+ * @param integer minimum number of selections.
+ */
+ public function setMinSelection($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MinSelection',$value,-1);
+ }
+
+ /**
+ * @return integer max number of selections. Defaults to -1, meaning not set.
+ */
+ public function getMaxSelection()
+ {
+ return $this->getViewState('MaxSelection',-1);
+ }
+
+ /**
+ * @param integer max number of selections.
+ */
+ public function setMaxSelection($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ $value=-1;
+ $this->setViewState('MaxSelection',$value,-1);
+ }
+
+ /**
+ * Get a comma separated list of required selected values.
+ * @return string comma separated list of required values.
+ */
+ public function getRequiredSelections()
+ {
+ return $this->getViewState('RequiredSelections','');
+ }
+
+ /**
+ * Set the list of required values, using aa comma separated list.
+ * @param string comma separated list of required values.
+ */
+ public function setRequiredSelections($value)
+ {
+ $this->setViewState('RequiredSelections',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input component changes its data
+ * from the InitialValue or the input component is not given.
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $control=$this->getValidationTarget();
+
+ $exists = true;
+ $values = $this->getSelection($control);
+ $count = count($values);
+ $required = $this->getRequiredValues();
+
+ //if required, check the values
+ if(!empty($required))
+ {
+ if($count < count($required) )
+ return false;
+ foreach($required as $require)
+ $exists = $exists && in_array($require, $values);
+ }
+
+ $min = $this->getMinSelection();
+ $max = $this->getMaxSelection();
+
+ if($min !== -1 && $max !== -1)
+ return $exists && $count >= $min && $count <= $max;
+ else if($min === -1 && $max !== -1)
+ return $exists && $count <= $max;
+ else if($min !== -1 && $max === -1)
+ return $exists && $count >= $min;
+ else
+ return $exists;
+ }
+
+ /**
+ * @param TListControl control to validate
+ * @return array number of selected values and its values.
+ */
+ protected function getSelection($control)
+ {
+ $values = array();
+
+ //get the data
+ foreach($control->getItems() as $item)
+ {
+ if($item->getSelected())
+ $values[] = $item->getValue();
+ }
+ return $values;
+ }
+
+ /**
+ * @return array list of required values.
+ */
+ protected function getRequiredValues()
+ {
+ $required = array();
+ $string = $this->getRequiredSelections();
+ if(!empty($string))
+ $required = preg_split('/,\s*/', $string);
+ return $required;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $control = $this->getValidationTarget();
+
+ if(!$control instanceof TListControl)
+ {
+ throw new TConfigurationException(
+ 'listcontrolvalidator_invalid_control',
+ $this->getID(),$this->getControlToValidate(), get_class($control));
+ }
+
+ $min = $this->getMinSelection();
+ $max = $this->getMaxSelection();
+ if($min !== -1)
+ $options['Min']= $min;
+ if($max !== -1)
+ $options['Max']= $max;
+ $required = $this->getRequiredSelections();
+ if(strlen($required) > 0)
+ $options['Required']= $required;
+ $options['TotalItems'] = $control->getItemCount();
+
+ return $options;
+ }
+}
diff --git a/framework/Web/UI/WebControls/TListItem.php b/framework/Web/UI/WebControls/TListItem.php
index 354aa62a..e80bcafd 100644
--- a/framework/Web/UI/WebControls/TListItem.php
+++ b/framework/Web/UI/WebControls/TListItem.php
@@ -1,184 +1,184 @@
-<?php
-/**
- * TListItem class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TListItem class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TListItem class.
- *
- * TListItem represents an item in a list control. Each item has a {@link setText Text}
- * property and a {@link setValue Value} property. If either one of them is not set,
- * it will take the value of the other property.
- * An item can be {@link setSelected Selected} or {@link setEnabled Enabled},
- * and it can have additional {@link getAttributes Attributes} which may be rendered
- * if the list control supports so.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TListItem extends TComponent
-{
- /**
- * @var TMap list of custom attributes
- */
- private $_attributes=null;
- /**
- * @var string text of the item
- */
- private $_text;
- /**
- * @var string value of the item
- */
- private $_value;
- /**
- * @var boolean whether the item is enabled
- */
- private $_enabled;
- /**
- * @var boolean whether the item is selected
- */
- private $_selected;
-
- /**
- * Constructor.
- * @param string text of the item
- * @param string value of the item
- * @param boolean whether the item is enabled
- * @param boolean whether the item is selected
- */
- public function __construct($text='',$value='',$enabled=true,$selected=false)
- {
- $this->setText($text);
- $this->setValue($value);
- $this->setEnabled($enabled);
- $this->setSelected($selected);
- }
-
- /**
- * @return boolean whether the item is enabled
- */
- public function getEnabled()
- {
- return $this->_enabled;
- }
-
- /**
- * @param boolean whether the item is enabled
- */
- public function setEnabled($value)
- {
- $this->_enabled=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether the item is selected
- */
- public function getSelected()
- {
- return $this->_selected;
- }
-
- /**
- * @param boolean whether the item is selected
- */
- public function setSelected($value)
- {
- $this->_selected=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return string text of the item
- */
- public function getText()
- {
- return $this->_text===''?$this->_value:$this->_text;
- }
-
- /**
- * @param string text of the item
- */
- public function setText($value)
- {
- $this->_text=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return string value of the item
- */
- public function getValue()
- {
- return $this->_value===''?$this->_text:$this->_value;
- }
-
- /**
- * @param string value of the item
- */
- public function setValue($value)
- {
- $this->_value=TPropertyValue::ensureString($value);
- }
-
- /**
- * @return TAttributeCollection custom attributes
- */
- public function getAttributes()
- {
- if(!$this->_attributes)
- $this->_attributes=new TAttributeCollection;
- return $this->_attributes;
- }
-
- /**
- * @return boolean whether the item has any custom attribute
- */
- public function getHasAttributes()
- {
- return $this->_attributes && $this->_attributes->getCount()>0;
- }
-
- /**
- * @param string name of the attribute
- * @return boolean whether the named attribute exists
- */
- public function hasAttribute($name)
- {
- return $this->_attributes?$this->_attributes->contains($name):false;
- }
-
- /**
- * @return string the named attribute value, null if attribute does not exist
- */
- public function getAttribute($name)
- {
- return $this->_attributes?$this->_attributes->itemAt($name):null;
- }
-
- /**
- * @param string attribute name
- * @param string value of the attribute
- */
- public function setAttribute($name,$value)
- {
- $this->getAttributes()->add($name,$value);
- }
-
- /**
- * Removes the named attribute.
- * @param string the name of the attribute to be removed.
- * @return string attribute value removed, empty string if attribute does not exist.
- */
- public function removeAttribute($name)
- {
- return $this->_attributes?$this->_attributes->remove($name):null;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TListItem class.
+ *
+ * TListItem represents an item in a list control. Each item has a {@link setText Text}
+ * property and a {@link setValue Value} property. If either one of them is not set,
+ * it will take the value of the other property.
+ * An item can be {@link setSelected Selected} or {@link setEnabled Enabled},
+ * and it can have additional {@link getAttributes Attributes} which may be rendered
+ * if the list control supports so.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TListItem extends TComponent
+{
+ /**
+ * @var TMap list of custom attributes
+ */
+ private $_attributes=null;
+ /**
+ * @var string text of the item
+ */
+ private $_text;
+ /**
+ * @var string value of the item
+ */
+ private $_value;
+ /**
+ * @var boolean whether the item is enabled
+ */
+ private $_enabled;
+ /**
+ * @var boolean whether the item is selected
+ */
+ private $_selected;
+
+ /**
+ * Constructor.
+ * @param string text of the item
+ * @param string value of the item
+ * @param boolean whether the item is enabled
+ * @param boolean whether the item is selected
+ */
+ public function __construct($text='',$value='',$enabled=true,$selected=false)
+ {
+ $this->setText($text);
+ $this->setValue($value);
+ $this->setEnabled($enabled);
+ $this->setSelected($selected);
+ }
+
+ /**
+ * @return boolean whether the item is enabled
+ */
+ public function getEnabled()
+ {
+ return $this->_enabled;
+ }
+
+ /**
+ * @param boolean whether the item is enabled
+ */
+ public function setEnabled($value)
+ {
+ $this->_enabled=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether the item is selected
+ */
+ public function getSelected()
+ {
+ return $this->_selected;
+ }
+
+ /**
+ * @param boolean whether the item is selected
+ */
+ public function setSelected($value)
+ {
+ $this->_selected=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return string text of the item
+ */
+ public function getText()
+ {
+ return $this->_text===''?$this->_value:$this->_text;
+ }
+
+ /**
+ * @param string text of the item
+ */
+ public function setText($value)
+ {
+ $this->_text=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return string value of the item
+ */
+ public function getValue()
+ {
+ return $this->_value===''?$this->_text:$this->_value;
+ }
+
+ /**
+ * @param string value of the item
+ */
+ public function setValue($value)
+ {
+ $this->_value=TPropertyValue::ensureString($value);
+ }
+
+ /**
+ * @return TAttributeCollection custom attributes
+ */
+ public function getAttributes()
+ {
+ if(!$this->_attributes)
+ $this->_attributes=new TAttributeCollection;
+ return $this->_attributes;
+ }
+
+ /**
+ * @return boolean whether the item has any custom attribute
+ */
+ public function getHasAttributes()
+ {
+ return $this->_attributes && $this->_attributes->getCount()>0;
+ }
+
+ /**
+ * @param string name of the attribute
+ * @return boolean whether the named attribute exists
+ */
+ public function hasAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->contains($name):false;
+ }
+
+ /**
+ * @return string the named attribute value, null if attribute does not exist
+ */
+ public function getAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->itemAt($name):null;
+ }
+
+ /**
+ * @param string attribute name
+ * @param string value of the attribute
+ */
+ public function setAttribute($name,$value)
+ {
+ $this->getAttributes()->add($name,$value);
+ }
+
+ /**
+ * Removes the named attribute.
+ * @param string the name of the attribute to be removed.
+ * @return string attribute value removed, empty string if attribute does not exist.
+ */
+ public function removeAttribute($name)
+ {
+ return $this->_attributes?$this->_attributes->remove($name):null;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TLiteral.php b/framework/Web/UI/WebControls/TLiteral.php
index 423e2d8e..e98d56bb 100644
--- a/framework/Web/UI/WebControls/TLiteral.php
+++ b/framework/Web/UI/WebControls/TLiteral.php
@@ -1,112 +1,112 @@
-<?php
-/**
- * TLiteral class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TLiteral class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TLiteral class
- *
- * TLiteral displays a static text on the Web page.
- * TLiteral is similar to the TLabel control, except that the TLiteral
- * control does not have style properties (e.g. BackColor, Font, etc.)
- * You can programmatically control the text displayed in the control by setting
- * the {@link setText Text} property. The text displayed may be HTML-encoded
- * if the {@link setEncode Encode} property is set true (defaults to false).
- *
- * TLiteral will render the contents enclosed within its component tag
- * if {@link setText Text} is empty.
- *
- * Note, if {@link setEncode Encode} is false, make sure {@link setText Text}
- * does not contain unwanted characters that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TLiteral extends TControl implements IDataRenderer
-{
- /**
- * @return string the static text of the TLiteral
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the static text of the TLiteral
- * @param string the text to be set
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the static text of the TLiteral.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the static text of the TLiteral
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the static text of the TLiteral.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the static text of the TLiteral
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
- */
- public function getEncode()
- {
- return $this->getViewState('Encode',false);
- }
-
- /**
- * @param boolean whether the rendered text should be HTML-encoded.
- */
- public function setEncode($value)
- {
- $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Renders the literal control.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if(($text=$this->getText())!=='')
- {
- if($this->getEncode())
- $writer->write(THttpUtility::htmlEncode($text));
- else
- $writer->write($text);
- }
- else
- parent::render($writer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TLiteral class
+ *
+ * TLiteral displays a static text on the Web page.
+ * TLiteral is similar to the TLabel control, except that the TLiteral
+ * control does not have style properties (e.g. BackColor, Font, etc.)
+ * You can programmatically control the text displayed in the control by setting
+ * the {@link setText Text} property. The text displayed may be HTML-encoded
+ * if the {@link setEncode Encode} property is set true (defaults to false).
+ *
+ * TLiteral will render the contents enclosed within its component tag
+ * if {@link setText Text} is empty.
+ *
+ * Note, if {@link setEncode Encode} is false, make sure {@link setText Text}
+ * does not contain unwanted characters that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TLiteral extends TControl implements IDataRenderer
+{
+ /**
+ * @return string the static text of the TLiteral
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the static text of the TLiteral
+ * @param string the text to be set
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the static text of the TLiteral.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the static text of the TLiteral
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the static text of the TLiteral.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the static text of the TLiteral
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
+ */
+ public function getEncode()
+ {
+ return $this->getViewState('Encode',false);
+ }
+
+ /**
+ * @param boolean whether the rendered text should be HTML-encoded.
+ */
+ public function setEncode($value)
+ {
+ $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Renders the literal control.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if(($text=$this->getText())!=='')
+ {
+ if($this->getEncode())
+ $writer->write(THttpUtility::htmlEncode($text));
+ else
+ $writer->write($text);
+ }
+ else
+ parent::render($writer);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TLiteralColumn.php b/framework/Web/UI/WebControls/TLiteralColumn.php
index 5b1353fc..48cbe013 100644
--- a/framework/Web/UI/WebControls/TLiteralColumn.php
+++ b/framework/Web/UI/WebControls/TLiteralColumn.php
@@ -1,154 +1,154 @@
-<?php
-/**
- * TLiteralColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TLiteralColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TLiteralColumn class
- *
- * TLiteralColumn represents a static text column that is bound to a field in a data source.
- * The cells in the column will be displayed with static texts using the data indexed by
- * {@link setDataField DataField}. You can customize the display by
- * setting {@link setDataFormatString DataFormatString}.
- *
- * If {@link setDataField DataField} is not specified, the cells will be filled
- * with {@link setText Text}.
- *
- * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
- * @package System.Web.UI.WebControls
- * @since 3.0.5
- */
-class TLiteralColumn extends TDataGridColumn
-{
- /**
- * @return string the field name from the data source to bind to the column
- */
- public function getDataField()
- {
- return $this->getViewState('DataField','');
- }
-
- /**
- * @param string the field name from the data source to bind to the column
- */
- public function setDataField($value)
- {
- $this->setViewState('DataField',$value,'');
- }
-
- /**
- * @return string the formatting string used to control how the bound data will be displayed.
- */
- public function getDataFormatString()
- {
- return $this->getViewState('DataFormatString','');
- }
-
- /**
- * @param string the formatting string used to control how the bound data will be displayed.
- */
- public function setDataFormatString($value)
- {
- $this->setViewState('DataFormatString',$value,'');
- }
-
- /**
- * @return string static text to be displayed in the column. Defaults to empty.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string static text to be displayed in the column.
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
- */
- public function getEncode()
- {
- return $this->getViewState('Encode',false);
- }
-
- /**
- * @param boolean whether the rendered text should be HTML-encoded.
- */
- public function setEncode($value)
- {
- $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem)
- {
- if($this->getDataField()!=='')
- $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- else
- {
- if(($dataField=$this->getDataField())!=='')
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- else
- {
- $text=$this->getText();
- if($this->getEncode())
- $text=THttpUtility::htmlEncode($text);
- $cell->setText($text);
- }
- }
- }
- else
- parent::initializeCell($cell,$columnIndex,$itemType);
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $data=$item->getData();
- $formatString=$this->getDataFormatString();
- if(($field=$this->getDataField())!=='')
- $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
- else
- $value=$this->formatDataValue($formatString,$data);
- if($sender instanceof TTableCell)
- {
- if($this->getEncode())
- $value=THttpUtility::htmlEncode($value);
- $sender->setText($value);
- }
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TLiteralColumn class
+ *
+ * TLiteralColumn represents a static text column that is bound to a field in a data source.
+ * The cells in the column will be displayed with static texts using the data indexed by
+ * {@link setDataField DataField}. You can customize the display by
+ * setting {@link setDataFormatString DataFormatString}.
+ *
+ * If {@link setDataField DataField} is not specified, the cells will be filled
+ * with {@link setText Text}.
+ *
+ * If {@link setEncode Encode} is true, the static texts will be HTML-encoded.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: TLiteralColumn.php 1397 2006-09-07 07:55:53Z wei $
+ * @package System.Web.UI.WebControls
+ * @since 3.0.5
+ */
+class TLiteralColumn extends TDataGridColumn
+{
+ /**
+ * @return string the field name from the data source to bind to the column
+ */
+ public function getDataField()
+ {
+ return $this->getViewState('DataField','');
+ }
+
+ /**
+ * @param string the field name from the data source to bind to the column
+ */
+ public function setDataField($value)
+ {
+ $this->setViewState('DataField',$value,'');
+ }
+
+ /**
+ * @return string the formatting string used to control how the bound data will be displayed.
+ */
+ public function getDataFormatString()
+ {
+ return $this->getViewState('DataFormatString','');
+ }
+
+ /**
+ * @param string the formatting string used to control how the bound data will be displayed.
+ */
+ public function setDataFormatString($value)
+ {
+ $this->setViewState('DataFormatString',$value,'');
+ }
+
+ /**
+ * @return string static text to be displayed in the column. Defaults to empty.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string static text to be displayed in the column.
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * @return boolean whether the rendered text should be HTML-encoded. Defaults to false.
+ */
+ public function getEncode()
+ {
+ return $this->getViewState('Encode',false);
+ }
+
+ /**
+ * @param boolean whether the rendered text should be HTML-encoded.
+ */
+ public function setEncode($value)
+ {
+ $this->setViewState('Encode',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::EditItem || $itemType===TListItemType::SelectedItem)
+ {
+ if($this->getDataField()!=='')
+ $cell->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ else
+ {
+ if(($dataField=$this->getDataField())!=='')
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ else
+ {
+ $text=$this->getText();
+ if($this->getEncode())
+ $text=THttpUtility::htmlEncode($text);
+ $cell->setText($text);
+ }
+ }
+ }
+ else
+ parent::initializeCell($cell,$columnIndex,$itemType);
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $data=$item->getData();
+ $formatString=$this->getDataFormatString();
+ if(($field=$this->getDataField())!=='')
+ $value=$this->formatDataValue($formatString,$this->getDataFieldValue($data,$field));
+ else
+ $value=$this->formatDataValue($formatString,$data);
+ if($sender instanceof TTableCell)
+ {
+ if($this->getEncode())
+ $value=THttpUtility::htmlEncode($value);
+ $sender->setText($value);
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TMarkdown.php b/framework/Web/UI/WebControls/TMarkdown.php
index 3aa1c9be..726a1ebe 100644
--- a/framework/Web/UI/WebControls/TMarkdown.php
+++ b/framework/Web/UI/WebControls/TMarkdown.php
@@ -1,75 +1,75 @@
-<?php
-/**
- * TMarkdown class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TMarkdown class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TTextHighlighter and MarkdownParser classes
- */
-Prado::using('System.Web.UI.WebControls.TTextHighlighter');
-Prado::using('System.3rdParty.Markdown.MarkdownParser');
-
-/**
- * TMarkdown class
- *
- * TMarkdown is a control that produces HTML from code with markdown syntax.
- *
- * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
- * you to write using an easy-to-read, easy-to-write plain text format, then
- * convert it to structurally valid XHTML (or HTML).
- * Further documentation regarding Markdown can be found at
- * http://daringfireball.net/projects/markdown/
- *
- * To use TMarkdown, simply enclose the content to be rendered within
- * the body of TMarkdown in a template.
- *
- * See http://www.pradosoft.com/demos/quickstart/?page=Markdown for
- * details on the Markdown syntax usage.
- *
- * TMarkdown also performs syntax highlighting for code blocks whose language
- * is recognized by {@link TTextHighlighter}.
- * The language of a code block must be specified in the first line of the block
- * and enclosed within a pair of square brackets (e.g. [php]).
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TMarkdown extends TTextHighlighter
-{
- /**
- * Processes a text string.
- * This method is required by the parent class.
- * @param string text string to be processed
- * @return string the processed text result
- */
- public function processText($text)
- {
- $renderer = new MarkdownParser;
- $result = $renderer->parse($text);
- return preg_replace_callback(
- '/<pre><code>\[\s*(\w+)\s*\]\n+((.|\n)*?)\s*<\\/code><\\/pre>/im',
- array($this, 'highlightCode'), $result);
- }
-
- /**
- * Highlights source code using TTextHighlighter
- * @param array matches of code blocks
- * @return string highlighted code.
- */
- protected function highlightCode($matches)
- {
- $text = html_entity_decode($matches[2],ENT_QUOTES,'UTF-8');
- $this->setLanguage($matches[1]);
- return parent::processText($text);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TTextHighlighter and MarkdownParser classes
+ */
+Prado::using('System.Web.UI.WebControls.TTextHighlighter');
+Prado::using('System.3rdParty.Markdown.MarkdownParser');
+
+/**
+ * TMarkdown class
+ *
+ * TMarkdown is a control that produces HTML from code with markdown syntax.
+ *
+ * Markdown is a text-to-HTML conversion tool for web writers. Markdown allows
+ * you to write using an easy-to-read, easy-to-write plain text format, then
+ * convert it to structurally valid XHTML (or HTML).
+ * Further documentation regarding Markdown can be found at
+ * http://daringfireball.net/projects/markdown/
+ *
+ * To use TMarkdown, simply enclose the content to be rendered within
+ * the body of TMarkdown in a template.
+ *
+ * See http://www.pradosoft.com/demos/quickstart/?page=Markdown for
+ * details on the Markdown syntax usage.
+ *
+ * TMarkdown also performs syntax highlighting for code blocks whose language
+ * is recognized by {@link TTextHighlighter}.
+ * The language of a code block must be specified in the first line of the block
+ * and enclosed within a pair of square brackets (e.g. [php]).
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TMarkdown extends TTextHighlighter
+{
+ /**
+ * Processes a text string.
+ * This method is required by the parent class.
+ * @param string text string to be processed
+ * @return string the processed text result
+ */
+ public function processText($text)
+ {
+ $renderer = new MarkdownParser;
+ $result = $renderer->parse($text);
+ return preg_replace_callback(
+ '/<pre><code>\[\s*(\w+)\s*\]\n+((.|\n)*?)\s*<\\/code><\\/pre>/im',
+ array($this, 'highlightCode'), $result);
+ }
+
+ /**
+ * Highlights source code using TTextHighlighter
+ * @param array matches of code blocks
+ * @return string highlighted code.
+ */
+ protected function highlightCode($matches)
+ {
+ $text = html_entity_decode($matches[2],ENT_QUOTES,'UTF-8');
+ $this->setLanguage($matches[1]);
+ return parent::processText($text);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TMultiView.php b/framework/Web/UI/WebControls/TMultiView.php
index 81d404b2..0c40cd06 100644
--- a/framework/Web/UI/WebControls/TMultiView.php
+++ b/framework/Web/UI/WebControls/TMultiView.php
@@ -1,378 +1,378 @@
-<?php
-/**
- * TMultiView and TView class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TMultiView class
- *
- * TMultiView serves as a container for a group of {@link TView} controls.
- * The view collection can be retrieved by {@link getViews Views}.
- * Each view contains child controls. TMultiView determines which view and its
- * child controls are visible. At any time, at most one view is visible (called
- * active). To make a view active, set {@link setActiveView ActiveView} or
- * {@link setActiveViewIndex ActiveViewIndex}.
- *
- * TMultiView also responds to specific command events raised from button controls
- * contained in current active view. A command event with name 'NextView'
- * will cause TMultiView to make the next available view active.
- * Other command names recognized by TMultiView include
- * - PreviousView : switch to previous view
- * - SwitchViewID : switch to a view by its ID path
- * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
- *
- * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
- * when its active view is changed during a postback.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TMultiView extends TControl
-{
- const CMD_NEXTVIEW='NextView';
- const CMD_PREVIOUSVIEW='PreviousView';
- const CMD_SWITCHVIEWID='SwitchViewID';
- const CMD_SWITCHVIEWINDEX='SwitchViewIndex';
- private $_cachedActiveViewIndex=-1;
- private $_ignoreBubbleEvents=false;
-
- /**
- * Processes an object that is created during parsing template.
- * This method overrides the parent implementation by adding only {@link TView}
- * controls as children.
- * @param string|TComponent text string or component parsed and instantiated in template
- * @see createdOnTemplate
- * @throws TConfigurationException if controls other than {@link TView} is being added
- */
- public function addParsedObject($object)
- {
- if($object instanceof TView)
- $this->getControls()->add($object);
- else if(!is_string($object))
- throw new TConfigurationException('multiview_view_required');
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TViewCollection control collection
- */
- protected function createControlCollection()
- {
- return new TViewCollection($this);
- }
-
- /**
- * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1.
- */
- public function getActiveViewIndex()
- {
- if($this->_cachedActiveViewIndex>-1)
- return $this->_cachedActiveViewIndex;
- else
- return $this->getControlState('ActiveViewIndex',-1);
- }
-
- /**
- * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
- * @throws TInvalidDataValueException if the view index is invalid
- */
- public function setActiveViewIndex($value)
- {
- if(($index=TPropertyValue::ensureInteger($value))<0)
- $index=-1;
- $views=$this->getViews();
- $count=$views->getCount();
- if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED)
- $this->_cachedActiveViewIndex=$index;
- else if($index<$count)
- {
- $this->setControlState('ActiveViewIndex',$index,-1);
- $this->_cachedActiveViewIndex=-1;
- if($index>=0)
- $this->activateView($views->itemAt($index),true);
- }
- else
- throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
- }
-
- /**
- * @return TView the currently active view, null if no active view
- * @throws TInvalidDataValueException if the current active view index is invalid
- */
- public function getActiveView()
- {
- $index=$this->getActiveViewIndex();
- $views=$this->getViews();
- if($index>=$views->getCount())
- throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
- if($index<0)
- return null;
- $view=$views->itemAt($index);
- if(!$view->getActive())
- $this->activateView($view,false);
- return $view;
- }
-
- /**
- * @param TView the view to be activated
- * @throws TInvalidOperationException if the view is not in the view collection
- */
- public function setActiveView($view)
- {
- if(($index=$this->getViews()->indexOf($view))>=0)
- $this->setActiveViewIndex($index);
- else
- throw new TInvalidOperationException('multiview_view_inexistent');
- }
-
- /**
- * Activates the specified view.
- * If there is any view currently active, it will be deactivated.
- * @param TView the view to be activated
- * @param boolean whether to trigger OnActiveViewChanged event.
- */
- protected function activateView($view,$triggerViewChangedEvent=true)
- {
- if($view->getActive())
- return;
- $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
- foreach($this->getViews() as $v)
- {
- if($v===$view)
- {
- $view->setActive(true);
- if($triggerEvent)
- {
- $view->onActivate(null);
- $this->onActiveViewChanged(null);
- }
- }
- else if($v->getActive())
- {
- $v->setActive(false);
- if($triggerEvent)
- $v->onDeactivate(null);
- }
- }
- }
-
- /**
- * @return TViewCollection the view collection
- */
- public function getViews()
- {
- return $this->getControls();
- }
-
- /**
- * Makes the multiview ignore all bubbled events.
- * This is method is used internally by framework and control
- * developers.
- */
- public function ignoreBubbleEvents()
- {
- $this->_ignoreBubbleEvents=true;
- }
-
- /**
- * Initializes the active view if any.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- if($this->_cachedActiveViewIndex>=0)
- $this->setActiveViewIndex($this->_cachedActiveViewIndex);
- }
-
- /**
- * Raises <b>OnActiveViewChanged</b> event.
- * The event is raised when the currently active view is changed to a new one
- * @param TEventParameter event parameter
- */
- public function onActiveViewChanged($param)
- {
- $this->raiseEvent('OnActiveViewChanged',$this,$param);
- }
-
- /**
- * Processes the events bubbled from child controls.
- * The method handles view-related command events.
- * @param TControl sender of the event
- * @param mixed event parameter
- * @return boolean whether this event is handled
- */
- public function bubbleEvent($sender,$param)
- {
- if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter))
- {
- switch($param->getCommandName())
- {
- case self::CMD_NEXTVIEW:
- if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1)
- $this->setActiveViewIndex($index+1);
- else
- $this->setActiveViewIndex(-1);
- return true;
- case self::CMD_PREVIOUSVIEW:
- if(($index=$this->getActiveViewIndex())>=0)
- $this->setActiveViewIndex($index-1);
- return true;
- case self::CMD_SWITCHVIEWID:
- $view=$this->findControl($viewID=$param->getCommandParameter());
- if($view!==null && $view->getParent()===$this)
- {
- $this->setActiveView($view);
- return true;
- }
- else
- throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID);
- case self::CMD_SWITCHVIEWINDEX:
- $index=TPropertyValue::ensureInteger($param->getCommandParameter());
- $this->setActiveViewIndex($index);
- return true;
- }
- }
- return false;
- }
-
- /**
- * Loads state into the wizard.
- * This method is invoked by the framework when the control state is being saved.
- */
- public function loadState()
- {
- // a dummy call to ensure the view is activated
- $this->getActiveView();
- }
-
- /**
- * Renders the currently active view.
- * @param THtmlWriter the writer for the rendering purpose.
- */
- public function render($writer)
- {
- if(($view=$this->getActiveView())!==null)
- $view->renderControl($writer);
- }
-}
-
-/**
- * TViewCollection class.
- * TViewCollection represents a collection that only takes {@link TView} instances
- * as collection elements.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TViewCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by ensuring only {@link TView}
- * controls be added into the collection.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TView)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('viewcollection_view_required');
- }
-}
-
-/**
- * TView class
- *
- * TView is a container for a group of controls. TView must be contained
- * within a {@link TMultiView} control in which only one view can be active
- * at one time.
- *
- * To activate a view, set {@link setActive Active} to true.
- * When a view is activated, it raises {@link onActivate OnActivate} event;
- * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TView extends TControl
-{
- private $_active=false;
-
- /**
- * Raises <b>OnActivate</b> event.
- * @param TEventParameter event parameter
- */
- public function onActivate($param)
- {
- $this->raiseEvent('OnActivate',$this,$param);
- }
-
- /**
- * Raises <b>OnDeactivate</b> event.
- * @param TEventParameter event parameter
- */
- public function onDeactivate($param)
- {
- $this->raiseEvent('OnDeactivate',$this,$param);
- }
-
- /**
- * @return boolean whether this view is active. Defaults to false.
- */
- public function getActive()
- {
- return $this->_active;
- }
-
- /**
- * @param boolean whether this view is active.
- */
- public function setActive($value)
- {
- $value=TPropertyValue::ensureBoolean($value);
- $this->_active=$value;
- parent::setVisible($value);
- }
-
- /**
- * @param boolean whether the parents should also be checked if visible
- * @return boolean whether this view is visible.
- * The view is visible if it is active and its parent is visible.
- */
- public function getVisible($checkParents=true)
- {
- if(($parent=$this->getParent())===null)
- return $this->getActive();
- else if($this->getActive())
- return $parent->getVisible($checkParents);
- else
- return false;
- }
-
- /**
- * @param boolean
- * @throws TInvalidOperationException whenever this method is invoked.
- */
- public function setVisible($value)
- {
- throw new TInvalidOperationException('view_visible_readonly');
- }
-}
-
+<?php
+/**
+ * TMultiView and TView class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TMultiView class
+ *
+ * TMultiView serves as a container for a group of {@link TView} controls.
+ * The view collection can be retrieved by {@link getViews Views}.
+ * Each view contains child controls. TMultiView determines which view and its
+ * child controls are visible. At any time, at most one view is visible (called
+ * active). To make a view active, set {@link setActiveView ActiveView} or
+ * {@link setActiveViewIndex ActiveViewIndex}.
+ *
+ * TMultiView also responds to specific command events raised from button controls
+ * contained in current active view. A command event with name 'NextView'
+ * will cause TMultiView to make the next available view active.
+ * Other command names recognized by TMultiView include
+ * - PreviousView : switch to previous view
+ * - SwitchViewID : switch to a view by its ID path
+ * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection.
+ *
+ * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event
+ * when its active view is changed during a postback.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TMultiView extends TControl
+{
+ const CMD_NEXTVIEW='NextView';
+ const CMD_PREVIOUSVIEW='PreviousView';
+ const CMD_SWITCHVIEWID='SwitchViewID';
+ const CMD_SWITCHVIEWINDEX='SwitchViewIndex';
+ private $_cachedActiveViewIndex=-1;
+ private $_ignoreBubbleEvents=false;
+
+ /**
+ * Processes an object that is created during parsing template.
+ * This method overrides the parent implementation by adding only {@link TView}
+ * controls as children.
+ * @param string|TComponent text string or component parsed and instantiated in template
+ * @see createdOnTemplate
+ * @throws TConfigurationException if controls other than {@link TView} is being added
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TView)
+ $this->getControls()->add($object);
+ else if(!is_string($object))
+ throw new TConfigurationException('multiview_view_required');
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TViewCollection control collection
+ */
+ protected function createControlCollection()
+ {
+ return new TViewCollection($this);
+ }
+
+ /**
+ * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1.
+ */
+ public function getActiveViewIndex()
+ {
+ if($this->_cachedActiveViewIndex>-1)
+ return $this->_cachedActiveViewIndex;
+ else
+ return $this->getControlState('ActiveViewIndex',-1);
+ }
+
+ /**
+ * @param integer the zero-based index of the current view in the view collection. -1 if no active view.
+ * @throws TInvalidDataValueException if the view index is invalid
+ */
+ public function setActiveViewIndex($value)
+ {
+ if(($index=TPropertyValue::ensureInteger($value))<0)
+ $index=-1;
+ $views=$this->getViews();
+ $count=$views->getCount();
+ if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED)
+ $this->_cachedActiveViewIndex=$index;
+ else if($index<$count)
+ {
+ $this->setControlState('ActiveViewIndex',$index,-1);
+ $this->_cachedActiveViewIndex=-1;
+ if($index>=0)
+ $this->activateView($views->itemAt($index),true);
+ }
+ else
+ throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
+ }
+
+ /**
+ * @return TView the currently active view, null if no active view
+ * @throws TInvalidDataValueException if the current active view index is invalid
+ */
+ public function getActiveView()
+ {
+ $index=$this->getActiveViewIndex();
+ $views=$this->getViews();
+ if($index>=$views->getCount())
+ throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index);
+ if($index<0)
+ return null;
+ $view=$views->itemAt($index);
+ if(!$view->getActive())
+ $this->activateView($view,false);
+ return $view;
+ }
+
+ /**
+ * @param TView the view to be activated
+ * @throws TInvalidOperationException if the view is not in the view collection
+ */
+ public function setActiveView($view)
+ {
+ if(($index=$this->getViews()->indexOf($view))>=0)
+ $this->setActiveViewIndex($index);
+ else
+ throw new TInvalidOperationException('multiview_view_inexistent');
+ }
+
+ /**
+ * Activates the specified view.
+ * If there is any view currently active, it will be deactivated.
+ * @param TView the view to be activated
+ * @param boolean whether to trigger OnActiveViewChanged event.
+ */
+ protected function activateView($view,$triggerViewChangedEvent=true)
+ {
+ if($view->getActive())
+ return;
+ $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
+ foreach($this->getViews() as $v)
+ {
+ if($v===$view)
+ {
+ $view->setActive(true);
+ if($triggerEvent)
+ {
+ $view->onActivate(null);
+ $this->onActiveViewChanged(null);
+ }
+ }
+ else if($v->getActive())
+ {
+ $v->setActive(false);
+ if($triggerEvent)
+ $v->onDeactivate(null);
+ }
+ }
+ }
+
+ /**
+ * @return TViewCollection the view collection
+ */
+ public function getViews()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * Makes the multiview ignore all bubbled events.
+ * This is method is used internally by framework and control
+ * developers.
+ */
+ public function ignoreBubbleEvents()
+ {
+ $this->_ignoreBubbleEvents=true;
+ }
+
+ /**
+ * Initializes the active view if any.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ if($this->_cachedActiveViewIndex>=0)
+ $this->setActiveViewIndex($this->_cachedActiveViewIndex);
+ }
+
+ /**
+ * Raises <b>OnActiveViewChanged</b> event.
+ * The event is raised when the currently active view is changed to a new one
+ * @param TEventParameter event parameter
+ */
+ public function onActiveViewChanged($param)
+ {
+ $this->raiseEvent('OnActiveViewChanged',$this,$param);
+ }
+
+ /**
+ * Processes the events bubbled from child controls.
+ * The method handles view-related command events.
+ * @param TControl sender of the event
+ * @param mixed event parameter
+ * @return boolean whether this event is handled
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter))
+ {
+ switch($param->getCommandName())
+ {
+ case self::CMD_NEXTVIEW:
+ if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1)
+ $this->setActiveViewIndex($index+1);
+ else
+ $this->setActiveViewIndex(-1);
+ return true;
+ case self::CMD_PREVIOUSVIEW:
+ if(($index=$this->getActiveViewIndex())>=0)
+ $this->setActiveViewIndex($index-1);
+ return true;
+ case self::CMD_SWITCHVIEWID:
+ $view=$this->findControl($viewID=$param->getCommandParameter());
+ if($view!==null && $view->getParent()===$this)
+ {
+ $this->setActiveView($view);
+ return true;
+ }
+ else
+ throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID);
+ case self::CMD_SWITCHVIEWINDEX:
+ $index=TPropertyValue::ensureInteger($param->getCommandParameter());
+ $this->setActiveViewIndex($index);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Loads state into the wizard.
+ * This method is invoked by the framework when the control state is being saved.
+ */
+ public function loadState()
+ {
+ // a dummy call to ensure the view is activated
+ $this->getActiveView();
+ }
+
+ /**
+ * Renders the currently active view.
+ * @param THtmlWriter the writer for the rendering purpose.
+ */
+ public function render($writer)
+ {
+ if(($view=$this->getActiveView())!==null)
+ $view->renderControl($writer);
+ }
+}
+
+/**
+ * TViewCollection class.
+ * TViewCollection represents a collection that only takes {@link TView} instances
+ * as collection elements.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TViewCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by ensuring only {@link TView}
+ * controls be added into the collection.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TView)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('viewcollection_view_required');
+ }
+}
+
+/**
+ * TView class
+ *
+ * TView is a container for a group of controls. TView must be contained
+ * within a {@link TMultiView} control in which only one view can be active
+ * at one time.
+ *
+ * To activate a view, set {@link setActive Active} to true.
+ * When a view is activated, it raises {@link onActivate OnActivate} event;
+ * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TView extends TControl
+{
+ private $_active=false;
+
+ /**
+ * Raises <b>OnActivate</b> event.
+ * @param TEventParameter event parameter
+ */
+ public function onActivate($param)
+ {
+ $this->raiseEvent('OnActivate',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnDeactivate</b> event.
+ * @param TEventParameter event parameter
+ */
+ public function onDeactivate($param)
+ {
+ $this->raiseEvent('OnDeactivate',$this,$param);
+ }
+
+ /**
+ * @return boolean whether this view is active. Defaults to false.
+ */
+ public function getActive()
+ {
+ return $this->_active;
+ }
+
+ /**
+ * @param boolean whether this view is active.
+ */
+ public function setActive($value)
+ {
+ $value=TPropertyValue::ensureBoolean($value);
+ $this->_active=$value;
+ parent::setVisible($value);
+ }
+
+ /**
+ * @param boolean whether the parents should also be checked if visible
+ * @return boolean whether this view is visible.
+ * The view is visible if it is active and its parent is visible.
+ */
+ public function getVisible($checkParents=true)
+ {
+ if(($parent=$this->getParent())===null)
+ return $this->getActive();
+ else if($this->getActive())
+ return $parent->getVisible($checkParents);
+ else
+ return false;
+ }
+
+ /**
+ * @param boolean
+ * @throws TInvalidOperationException whenever this method is invoked.
+ */
+ public function setVisible($value)
+ {
+ throw new TInvalidOperationException('view_visible_readonly');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TOutputCache.php b/framework/Web/UI/WebControls/TOutputCache.php
index 64e4ff42..cc79e76f 100644
--- a/framework/Web/UI/WebControls/TOutputCache.php
+++ b/framework/Web/UI/WebControls/TOutputCache.php
@@ -1,621 +1,621 @@
-<?php
-/**
- * TOutputCache class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TOutputCache class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TOutputCache class.
- *
- * TOutputCache enables caching a portion of a Web page, also known as
- * partial caching. The content being cached can be either static or
- * dynamic.
- *
- * To use TOutputCache, simply enclose the content to be cached
- * within the TOutputCache component tag on a template, e.g.,
- * <code>
- * <com:TOutputCache>
- * content to be cached
- * </com:TOutputCache>
- * </code>
- * where content to be cached can be static text and/or component tags.
- *
- * The validity of the cached content is determined based on two factors:
- * the {@link setDuration Duration} and the cache dependency.
- * The former specifies the number of seconds that the data can remain
- * valid in cache (defaults to 60s), while the latter specifies conditions
- * that the cached data depends on. If a dependency changes,
- * (e.g. relevant data in DB are updated), the cached data will be invalidated.
- *
- * There are two ways to specify cache dependency. One may write event handlers
- * to respond to the {@link onCheckDependency OnCheckDependency} event and set
- * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
- * property to indicate whether the cached data remains valid or not.
- * One can also extend TOutputCache and override its {@link getCacheDependency}
- * function. While the former is easier to use, the latter offers more extensibility.
- *
- * The content fetched from cache may be variated with respect to
- * some parameters. It supports variation with respect to request parameters,
- * which is specified by {@link setVaryByParam VaryByParam} property.
- * If a specified request parameter is different, a different version of
- * cached content is used. This is extremely useful if a page's content
- * may be variated according to some GET parameters.
- * The content being cached may also be variated with user sessions if
- * {@link setVaryBySession VaryBySession} is set true.
- * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
- *
- * Output caches can be nested. An outer cache takes precedence over an
- * inner cache. This means, if the content cached by the inner cache expires
- * or is invalidated, while that by the outer cache not, the outer cached
- * content will be used.
- *
- * Note, TOutputCache is effective only for non-postback page requests
- * and when cache module is enabled.
- *
- * Do not attempt to address child controls of TOutputCache when the cached
- * content is to be used. Use {@link getContentCached ContentCached} property
- * to determine whether the content is cached or not.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TOutputCache extends TControl implements INamingContainer
-{
- const CACHE_ID_PREFIX='prado:outputcache';
- private $_cacheModuleID='';
- private $_dataCached=false;
- private $_cacheAvailable=false;
- private $_cacheChecked=false;
- private $_cacheKey=null;
- private $_duration=60;
- private $_cache=null;
- private $_contents;
- private $_state;
- private $_actions=array();
- private $_varyByParam='';
- private $_keyPrefix='';
- private $_varyBySession=false;
- private $_cachePostBack=false;
- private $_cacheTime=0;
-
- /**
- * Returns a value indicating whether body contents are allowed for this control.
- * This method overrides the parent implementation by checking if cached
- * content is available or not. If yes, it returns false, otherwise true.
- * @param boolean whether body contents are allowed for this control.
- */
- public function getAllowChildControls()
- {
- $this->determineCacheability();
- return !$this->_dataCached;
- }
-
- private function determineCacheability()
- {
- if(!$this->_cacheChecked)
- {
- $this->_cacheChecked=true;
- if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
- {
- if($this->_cacheModuleID!=='')
- {
- $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
- if(!($this->_cache instanceof ICache))
- throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
- }
- else
- $this->_cache=$this->getApplication()->getCache();
- if($this->_cache!==null)
- {
- $this->_cacheAvailable=true;
- $data=$this->_cache->get($this->getCacheKey());
- if(is_array($data))
- {
- $param=new TOutputCacheCheckDependencyEventParameter;
- $param->setCacheTime(isset($data[3])?$data[3]:0);
- $this->onCheckDependency($param);
- $this->_dataCached=$param->getIsValid();
- }
- else
- $this->_dataCached=false;
- if($this->_dataCached)
- list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
- }
- }
- }
- }
-
- /**
- * Performs the Init step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function initRecursive($namingContainer=null)
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::initRecursive($namingContainer);
- $stack->pop();
- }
- else
- parent::initRecursive($namingContainer);
- }
-
- /**
- * Performs the Load step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page. If the data is restored
- * from cache, it also recovers the actions associated with the cached data.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function loadRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::loadRecursive();
- $stack->pop();
- }
- else
- {
- if($this->_dataCached)
- $this->performActions();
- parent::loadRecursive();
- }
- }
-
- private function performActions()
- {
- $page=$this->getPage();
- $cs=$page->getClientScript();
- foreach($this->_actions as $action)
- {
- if($action[0]==='Page.ClientScript')
- call_user_func_array(array($cs,$action[1]),$action[2]);
- else if($action[0]==='Page')
- call_user_func_array(array($page,$action[1]),$action[2]);
- else
- call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
- }
- }
-
- /**
- * Performs the PreRender step for the control and all its child controls.
- * This method overrides the parent implementation by setting up
- * the stack of the output cache in the page.
- * Only framework developers should use this method.
- * @param TControl the naming container control
- */
- protected function preRenderRecursive()
- {
- if($this->_cacheAvailable && !$this->_dataCached)
- {
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::preRenderRecursive();
- $stack->pop();
- }
- else
- parent::preRenderRecursive();
- }
-
- /**
- * Loads state (viewstate and controlstate) into a control and its children.
- * This method overrides the parent implementation by loading
- * cached state if available.
- * This method should only be used by framework developers.
- * @param array the collection of the state
- * @param boolean whether the viewstate should be loaded
- */
- protected function loadStateRecursive(&$state,$needViewState=true)
- {
- $st=unserialize($state);
- parent::loadStateRecursive($st,$needViewState);
- }
-
- /**
- * Saves all control state (viewstate and controlstate) as a collection.
- * This method overrides the parent implementation by saving state
- * into cache if needed.
- * This method should only be used by framework developers.
- * @param boolean whether the viewstate should be saved
- * @return array the collection of the control state (including its children's state).
- */
- protected function &saveStateRecursive($needViewState=true)
- {
- if($this->_dataCached)
- return $this->_state;
- else
- {
- $st=parent::saveStateRecursive($needViewState);
- // serialization is needed to avoid undefined classes when loading state
- $this->_state=serialize($st);
- return $this->_state;
- }
- }
-
- /**
- * Registers an action associated with the content being cached.
- * The registered action will be replayed if the content stored
- * in the cache is served to end-users.
- * @param string context of the action method. This is a property-path
- * referring to the context object (e.g. Page, Page.ClientScript)
- * @param string method name of the context object
- * @param array list of parameters to be passed to the action method
- */
- public function registerAction($context,$funcName,$funcParams)
- {
- $this->_actions[]=array($context,$funcName,$funcParams);
- }
-
- public function getCacheKey()
- {
- if($this->_cacheKey===null)
- $this->_cacheKey=$this->calculateCacheKey();
- return $this->_cacheKey;
- }
-
- /**
- * Calculates the cache key.
- * The key is calculated based on the unique ID of this control
- * and the request parameters specified via {@link setVaryByParam VaryByParam}.
- * If {@link getVaryBySession VaryBySession} is true, the session ID
- * will also participate in the key calculation.
- * This method may be overriden to support other variations in
- * the calculated cache key.
- * @return string cache key
- */
- protected function calculateCacheKey()
- {
- $key=$this->getBaseCacheKey();
- if($this->_varyBySession)
- $key.=$this->getSession()->getSessionID();
- if($this->_varyByParam!=='')
- {
- $params=array();
- $request=$this->getRequest();
- foreach(explode(',',$this->_varyByParam) as $name)
- {
- $name=trim($name);
- $params[$name]=$request->itemAt($name);
- }
- $key.=serialize($params);
- }
- $param=new TOutputCacheCalculateKeyEventParameter;
- $this->onCalculateKey($param);
- $key.=$param->getCacheKey();
- return $key;
- }
-
- /**
- * @return string basic cache key without variations
- */
- protected function getBaseCacheKey()
- {
- return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
- }
-
- /**
- * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
- */
- public function getCacheModuleID()
- {
- return $this->_cacheModuleID;
- }
-
- /**
- * @param string the ID of the cache module. If empty, the primary cache module will be used.
- */
- public function setCacheModuleID($value)
- {
- $this->_cacheModuleID=$value;
- }
-
- /**
- * Sets the prefix of the cache key.
- * This method is used internally by {@link TTemplate}.
- * @param string key prefix
- */
- public function setCacheKeyPrefix($value)
- {
- $this->_keyPrefix=$value;
- }
-
- /**
- * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * Returns the dependency of the data to be cached.
- * The default implementation simply returns null, meaning no specific dependency.
- * This method may be overriden to associate the data to be cached
- * with additional dependencies.
- * @return ICacheDependency
- */
- protected function getCacheDependency()
- {
- return null;
- }
-
- /**
- * @return boolean whether content enclosed is cached or not
- */
- public function getContentCached()
- {
- return $this->_dataCached;
- }
-
- /**
- * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
- * Note, if cache dependency changes or cache space is limited,
- * the data may be purged out of cache earlier.
- */
- public function getDuration()
- {
- return $this->_duration;
- }
-
- /**
- * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
- * @throws TInvalidDataValueException if the value is smaller than 0.
- */
- public function setDuration($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
- $this->_duration=$value;
- }
-
- /**
- * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
- */
- public function getVaryByParam()
- {
- return $this->_varyByParam;
- }
-
- /**
- * Sets the names of the request parameters that should be used in calculating the cache key.
- * The names should be concatenated by semicolons.
- * By setting this value, the output cache will use different cached data
- * for each different set of request parameter values.
- * @return string a semicolon-separated list of strings used to vary the output cache.
- */
- public function setVaryByParam($value)
- {
- $this->_varyByParam=trim($value);
- }
-
- /**
- * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
- */
- public function getVaryBySession()
- {
- return $this->_varyBySession;
- }
-
- /**
- * @param boolean whether the content being cached should be differentiated according to user sessions.
- */
- public function setVaryBySession($value)
- {
- $this->_varyBySession=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return boolean whether cached output will be used on postback requests. Defaults to false.
- */
- public function getCachingPostBack()
- {
- return $this->_cachePostBack;
- }
-
- /**
- * Sets a value indicating whether cached output will be used on postback requests.
- * By default, this is disabled. Be very cautious when enabling it.
- * If the cached content including interactive user controls such as
- * TTextBox, TDropDownList, your page may fail to render on postbacks.
- * @param boolean whether cached output will be used on postback requests.
- */
- public function setCachingPostBack($value)
- {
- $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * This event is raised when the output cache is checking cache dependency.
- * An event handler may be written to check customized dependency conditions.
- * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
- * property of the event parameter (which defaults to true).
- * @param TOutputCacheCheckDependencyEventParameter event parameter
- */
- public function onCheckDependency($param)
- {
- $this->raiseEvent('OnCheckDependency',$this,$param);
- }
-
- /**
- * This event is raised when the output cache is calculating cache key.
- * By varying cache keys, one can obtain different versions of cached content.
- * An event handler may be written to add variety of the key calculation.
- * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
- * this event parameter will be appended to the default key calculation scheme.
- * @param TOutputCacheCalculateKeyEventParameter event parameter
- */
- public function onCalculateKey($param)
- {
- $this->raiseEvent('OnCalculateKey',$this,$param);
- }
-
- /**
- * Renders the output cache control.
- * This method overrides the parent implementation by capturing the output
- * from its child controls and saving it into cache, if output cache is needed.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- if($this->_dataCached)
- $writer->write($this->_contents);
- else if($this->_cacheAvailable)
- {
- $textwriter = new TTextWriter();
- $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
-
- $stack=$this->getPage()->getCachingStack();
- $stack->push($this);
- parent::render($htmlWriter);
- $stack->pop();
-
- $content=$textwriter->flush();
- $data=array($content,$this->_state,$this->_actions,time());
- $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
- }
- else
- parent::render($writer);
- }
-}
-
-/**
- * TOutputCacheCheckDependencyEventParameter class
- *
- * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
- * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCheckDependencyEventParameter extends TEventParameter
-{
- private $_isValid=true;
- private $_cacheTime=0;
-
- /**
- * @return boolean whether the dependency remains valid. Defaults to true.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
-
- /**
- * @param boolean whether the dependency remains valid
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
- * @since 3.1.1
- */
- public function getCacheTime()
- {
- return $this->_cacheTime;
- }
-
- /**
- * @param integer the timestamp of the cached result. This is used internally.
- * @since 3.1.1
- */
- public function setCacheTime($value)
- {
- $this->_cacheTime=TPropertyValue::ensureInteger($value);
- }
-}
-
-
-/**
- * TOutputCacheCalculateKeyEventParameter class
- *
- * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
- * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TOutputCacheCalculateKeyEventParameter extends TEventParameter
-{
- /**
- * @var string cache key to be appended to the default calculation scheme.
- */
- private $_cacheKey='';
-
- /**
- * @return string cache key to be appended to the default calculation scheme.
- */
- public function getCacheKey()
- {
- return $this->_cacheKey;
- }
-
- /**
- * @param string cache key to be appended to the default calculation scheme
- */
- public function setCacheKey($value)
- {
- $this->_cacheKey=TPropertyValue::ensureString($value);
- }
-}
-
-/**
- * TOutputCacheTextWriterMulti class
- *
- * TOutputCacheTextWriterMulti is an internal class used by
- * TOutputCache to write simultaneously to multiple writers.
- *
- * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TOutputCacheTextWriterMulti extends TTextWriter
-{
- protected $_writers;
-
- public function __construct(Array $writers)
- {
- //parent::__construct();
- $this->_writers = $writers;
- }
-
- public function write($s)
- {
- foreach($this->_writers as $writer)
- $writer->write($s);
- }
-
- public function flush()
- {
- foreach($this->_writers as $writer)
- $s = $writer->flush();
- return $s;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TOutputCache class.
+ *
+ * TOutputCache enables caching a portion of a Web page, also known as
+ * partial caching. The content being cached can be either static or
+ * dynamic.
+ *
+ * To use TOutputCache, simply enclose the content to be cached
+ * within the TOutputCache component tag on a template, e.g.,
+ * <code>
+ * <com:TOutputCache>
+ * content to be cached
+ * </com:TOutputCache>
+ * </code>
+ * where content to be cached can be static text and/or component tags.
+ *
+ * The validity of the cached content is determined based on two factors:
+ * the {@link setDuration Duration} and the cache dependency.
+ * The former specifies the number of seconds that the data can remain
+ * valid in cache (defaults to 60s), while the latter specifies conditions
+ * that the cached data depends on. If a dependency changes,
+ * (e.g. relevant data in DB are updated), the cached data will be invalidated.
+ *
+ * There are two ways to specify cache dependency. One may write event handlers
+ * to respond to the {@link onCheckDependency OnCheckDependency} event and set
+ * the event parameter's {@link TOutputCacheCheckDependencyEventParameter::getIsValid IsValid}
+ * property to indicate whether the cached data remains valid or not.
+ * One can also extend TOutputCache and override its {@link getCacheDependency}
+ * function. While the former is easier to use, the latter offers more extensibility.
+ *
+ * The content fetched from cache may be variated with respect to
+ * some parameters. It supports variation with respect to request parameters,
+ * which is specified by {@link setVaryByParam VaryByParam} property.
+ * If a specified request parameter is different, a different version of
+ * cached content is used. This is extremely useful if a page's content
+ * may be variated according to some GET parameters.
+ * The content being cached may also be variated with user sessions if
+ * {@link setVaryBySession VaryBySession} is set true.
+ * To variate the cached content by other factors, override {@link calculateCacheKey()} method.
+ *
+ * Output caches can be nested. An outer cache takes precedence over an
+ * inner cache. This means, if the content cached by the inner cache expires
+ * or is invalidated, while that by the outer cache not, the outer cached
+ * content will be used.
+ *
+ * Note, TOutputCache is effective only for non-postback page requests
+ * and when cache module is enabled.
+ *
+ * Do not attempt to address child controls of TOutputCache when the cached
+ * content is to be used. Use {@link getContentCached ContentCached} property
+ * to determine whether the content is cached or not.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TOutputCache extends TControl implements INamingContainer
+{
+ const CACHE_ID_PREFIX='prado:outputcache';
+ private $_cacheModuleID='';
+ private $_dataCached=false;
+ private $_cacheAvailable=false;
+ private $_cacheChecked=false;
+ private $_cacheKey=null;
+ private $_duration=60;
+ private $_cache=null;
+ private $_contents;
+ private $_state;
+ private $_actions=array();
+ private $_varyByParam='';
+ private $_keyPrefix='';
+ private $_varyBySession=false;
+ private $_cachePostBack=false;
+ private $_cacheTime=0;
+
+ /**
+ * Returns a value indicating whether body contents are allowed for this control.
+ * This method overrides the parent implementation by checking if cached
+ * content is available or not. If yes, it returns false, otherwise true.
+ * @param boolean whether body contents are allowed for this control.
+ */
+ public function getAllowChildControls()
+ {
+ $this->determineCacheability();
+ return !$this->_dataCached;
+ }
+
+ private function determineCacheability()
+ {
+ if(!$this->_cacheChecked)
+ {
+ $this->_cacheChecked=true;
+ if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack()))
+ {
+ if($this->_cacheModuleID!=='')
+ {
+ $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID);
+ if(!($this->_cache instanceof ICache))
+ throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID);
+ }
+ else
+ $this->_cache=$this->getApplication()->getCache();
+ if($this->_cache!==null)
+ {
+ $this->_cacheAvailable=true;
+ $data=$this->_cache->get($this->getCacheKey());
+ if(is_array($data))
+ {
+ $param=new TOutputCacheCheckDependencyEventParameter;
+ $param->setCacheTime(isset($data[3])?$data[3]:0);
+ $this->onCheckDependency($param);
+ $this->_dataCached=$param->getIsValid();
+ }
+ else
+ $this->_dataCached=false;
+ if($this->_dataCached)
+ list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data;
+ }
+ }
+ }
+ }
+
+ /**
+ * Performs the Init step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function initRecursive($namingContainer=null)
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::initRecursive($namingContainer);
+ $stack->pop();
+ }
+ else
+ parent::initRecursive($namingContainer);
+ }
+
+ /**
+ * Performs the Load step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page. If the data is restored
+ * from cache, it also recovers the actions associated with the cached data.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function loadRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::loadRecursive();
+ $stack->pop();
+ }
+ else
+ {
+ if($this->_dataCached)
+ $this->performActions();
+ parent::loadRecursive();
+ }
+ }
+
+ private function performActions()
+ {
+ $page=$this->getPage();
+ $cs=$page->getClientScript();
+ foreach($this->_actions as $action)
+ {
+ if($action[0]==='Page.ClientScript')
+ call_user_func_array(array($cs,$action[1]),$action[2]);
+ else if($action[0]==='Page')
+ call_user_func_array(array($page,$action[1]),$action[2]);
+ else
+ call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]);
+ }
+ }
+
+ /**
+ * Performs the PreRender step for the control and all its child controls.
+ * This method overrides the parent implementation by setting up
+ * the stack of the output cache in the page.
+ * Only framework developers should use this method.
+ * @param TControl the naming container control
+ */
+ protected function preRenderRecursive()
+ {
+ if($this->_cacheAvailable && !$this->_dataCached)
+ {
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::preRenderRecursive();
+ $stack->pop();
+ }
+ else
+ parent::preRenderRecursive();
+ }
+
+ /**
+ * Loads state (viewstate and controlstate) into a control and its children.
+ * This method overrides the parent implementation by loading
+ * cached state if available.
+ * This method should only be used by framework developers.
+ * @param array the collection of the state
+ * @param boolean whether the viewstate should be loaded
+ */
+ protected function loadStateRecursive(&$state,$needViewState=true)
+ {
+ $st=unserialize($state);
+ parent::loadStateRecursive($st,$needViewState);
+ }
+
+ /**
+ * Saves all control state (viewstate and controlstate) as a collection.
+ * This method overrides the parent implementation by saving state
+ * into cache if needed.
+ * This method should only be used by framework developers.
+ * @param boolean whether the viewstate should be saved
+ * @return array the collection of the control state (including its children's state).
+ */
+ protected function &saveStateRecursive($needViewState=true)
+ {
+ if($this->_dataCached)
+ return $this->_state;
+ else
+ {
+ $st=parent::saveStateRecursive($needViewState);
+ // serialization is needed to avoid undefined classes when loading state
+ $this->_state=serialize($st);
+ return $this->_state;
+ }
+ }
+
+ /**
+ * Registers an action associated with the content being cached.
+ * The registered action will be replayed if the content stored
+ * in the cache is served to end-users.
+ * @param string context of the action method. This is a property-path
+ * referring to the context object (e.g. Page, Page.ClientScript)
+ * @param string method name of the context object
+ * @param array list of parameters to be passed to the action method
+ */
+ public function registerAction($context,$funcName,$funcParams)
+ {
+ $this->_actions[]=array($context,$funcName,$funcParams);
+ }
+
+ public function getCacheKey()
+ {
+ if($this->_cacheKey===null)
+ $this->_cacheKey=$this->calculateCacheKey();
+ return $this->_cacheKey;
+ }
+
+ /**
+ * Calculates the cache key.
+ * The key is calculated based on the unique ID of this control
+ * and the request parameters specified via {@link setVaryByParam VaryByParam}.
+ * If {@link getVaryBySession VaryBySession} is true, the session ID
+ * will also participate in the key calculation.
+ * This method may be overriden to support other variations in
+ * the calculated cache key.
+ * @return string cache key
+ */
+ protected function calculateCacheKey()
+ {
+ $key=$this->getBaseCacheKey();
+ if($this->_varyBySession)
+ $key.=$this->getSession()->getSessionID();
+ if($this->_varyByParam!=='')
+ {
+ $params=array();
+ $request=$this->getRequest();
+ foreach(explode(',',$this->_varyByParam) as $name)
+ {
+ $name=trim($name);
+ $params[$name]=$request->itemAt($name);
+ }
+ $key.=serialize($params);
+ }
+ $param=new TOutputCacheCalculateKeyEventParameter;
+ $this->onCalculateKey($param);
+ $key.=$param->getCacheKey();
+ return $key;
+ }
+
+ /**
+ * @return string basic cache key without variations
+ */
+ protected function getBaseCacheKey()
+ {
+ return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID();
+ }
+
+ /**
+ * @return string the ID of the cache module. Defaults to '', meaning the primary cache module is used.
+ */
+ public function getCacheModuleID()
+ {
+ return $this->_cacheModuleID;
+ }
+
+ /**
+ * @param string the ID of the cache module. If empty, the primary cache module will be used.
+ */
+ public function setCacheModuleID($value)
+ {
+ $this->_cacheModuleID=$value;
+ }
+
+ /**
+ * Sets the prefix of the cache key.
+ * This method is used internally by {@link TTemplate}.
+ * @param string key prefix
+ */
+ public function setCacheKeyPrefix($value)
+ {
+ $this->_keyPrefix=$value;
+ }
+
+ /**
+ * @return integer the timestamp of the cached content. This is only valid if the content is being cached.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * Returns the dependency of the data to be cached.
+ * The default implementation simply returns null, meaning no specific dependency.
+ * This method may be overriden to associate the data to be cached
+ * with additional dependencies.
+ * @return ICacheDependency
+ */
+ protected function getCacheDependency()
+ {
+ return null;
+ }
+
+ /**
+ * @return boolean whether content enclosed is cached or not
+ */
+ public function getContentCached()
+ {
+ return $this->_dataCached;
+ }
+
+ /**
+ * @return integer number of seconds that the data can remain in cache. Defaults to 60 seconds.
+ * Note, if cache dependency changes or cache space is limited,
+ * the data may be purged out of cache earlier.
+ */
+ public function getDuration()
+ {
+ return $this->_duration;
+ }
+
+ /**
+ * @param integer number of seconds that the data can remain in cache. If 0, it means data is not cached.
+ * @throws TInvalidDataValueException if the value is smaller than 0.
+ */
+ public function setDuration($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this));
+ $this->_duration=$value;
+ }
+
+ /**
+ * @return string a semicolon-separated list of strings used to vary the output cache. Defaults to ''.
+ */
+ public function getVaryByParam()
+ {
+ return $this->_varyByParam;
+ }
+
+ /**
+ * Sets the names of the request parameters that should be used in calculating the cache key.
+ * The names should be concatenated by semicolons.
+ * By setting this value, the output cache will use different cached data
+ * for each different set of request parameter values.
+ * @return string a semicolon-separated list of strings used to vary the output cache.
+ */
+ public function setVaryByParam($value)
+ {
+ $this->_varyByParam=trim($value);
+ }
+
+ /**
+ * @return boolean whether the content being cached should be differentiated according to user sessions. Defaults to false.
+ */
+ public function getVaryBySession()
+ {
+ return $this->_varyBySession;
+ }
+
+ /**
+ * @param boolean whether the content being cached should be differentiated according to user sessions.
+ */
+ public function setVaryBySession($value)
+ {
+ $this->_varyBySession=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return boolean whether cached output will be used on postback requests. Defaults to false.
+ */
+ public function getCachingPostBack()
+ {
+ return $this->_cachePostBack;
+ }
+
+ /**
+ * Sets a value indicating whether cached output will be used on postback requests.
+ * By default, this is disabled. Be very cautious when enabling it.
+ * If the cached content including interactive user controls such as
+ * TTextBox, TDropDownList, your page may fail to render on postbacks.
+ * @param boolean whether cached output will be used on postback requests.
+ */
+ public function setCachingPostBack($value)
+ {
+ $this->_cachePostBack=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * This event is raised when the output cache is checking cache dependency.
+ * An event handler may be written to check customized dependency conditions.
+ * The checking result should be saved by setting {@link TOutputCacheCheckDependencyEventParameter::setIsValid IsValid}
+ * property of the event parameter (which defaults to true).
+ * @param TOutputCacheCheckDependencyEventParameter event parameter
+ */
+ public function onCheckDependency($param)
+ {
+ $this->raiseEvent('OnCheckDependency',$this,$param);
+ }
+
+ /**
+ * This event is raised when the output cache is calculating cache key.
+ * By varying cache keys, one can obtain different versions of cached content.
+ * An event handler may be written to add variety of the key calculation.
+ * The value set in {@link TOutputCacheCalculateKeyEventParameter::setCacheKey CacheKey} of
+ * this event parameter will be appended to the default key calculation scheme.
+ * @param TOutputCacheCalculateKeyEventParameter event parameter
+ */
+ public function onCalculateKey($param)
+ {
+ $this->raiseEvent('OnCalculateKey',$this,$param);
+ }
+
+ /**
+ * Renders the output cache control.
+ * This method overrides the parent implementation by capturing the output
+ * from its child controls and saving it into cache, if output cache is needed.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ if($this->_dataCached)
+ $writer->write($this->_contents);
+ else if($this->_cacheAvailable)
+ {
+ $textwriter = new TTextWriter();
+ $multiwriter = new TOutputCacheTextWriterMulti(array($writer->getWriter(),$textwriter));
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), $multiwriter);
+
+ $stack=$this->getPage()->getCachingStack();
+ $stack->push($this);
+ parent::render($htmlWriter);
+ $stack->pop();
+
+ $content=$textwriter->flush();
+ $data=array($content,$this->_state,$this->_actions,time());
+ $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency());
+ }
+ else
+ parent::render($writer);
+ }
+}
+
+/**
+ * TOutputCacheCheckDependencyEventParameter class
+ *
+ * TOutputCacheCheckDependencyEventParameter encapsulates the parameter data for
+ * <b>OnCheckDependency</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCheckDependencyEventParameter extends TEventParameter
+{
+ private $_isValid=true;
+ private $_cacheTime=0;
+
+ /**
+ * @return boolean whether the dependency remains valid. Defaults to true.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+
+ /**
+ * @param boolean whether the dependency remains valid
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return integer the timestamp of the cached result. You may use this to help determine any dependency is changed.
+ * @since 3.1.1
+ */
+ public function getCacheTime()
+ {
+ return $this->_cacheTime;
+ }
+
+ /**
+ * @param integer the timestamp of the cached result. This is used internally.
+ * @since 3.1.1
+ */
+ public function setCacheTime($value)
+ {
+ $this->_cacheTime=TPropertyValue::ensureInteger($value);
+ }
+}
+
+
+/**
+ * TOutputCacheCalculateKeyEventParameter class
+ *
+ * TOutputCacheCalculateKeyEventParameter encapsulates the parameter data for
+ * <b>OnCalculateKey</b> event of {@link TOutputCache} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TOutputCacheCalculateKeyEventParameter extends TEventParameter
+{
+ /**
+ * @var string cache key to be appended to the default calculation scheme.
+ */
+ private $_cacheKey='';
+
+ /**
+ * @return string cache key to be appended to the default calculation scheme.
+ */
+ public function getCacheKey()
+ {
+ return $this->_cacheKey;
+ }
+
+ /**
+ * @param string cache key to be appended to the default calculation scheme
+ */
+ public function setCacheKey($value)
+ {
+ $this->_cacheKey=TPropertyValue::ensureString($value);
+ }
+}
+
+/**
+ * TOutputCacheTextWriterMulti class
+ *
+ * TOutputCacheTextWriterMulti is an internal class used by
+ * TOutputCache to write simultaneously to multiple writers.
+ *
+ * @author Gabor Berczi, DevWorx Hungary <gabor.berczi@devworx.hu>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TOutputCacheTextWriterMulti extends TTextWriter
+{
+ protected $_writers;
+
+ public function __construct(Array $writers)
+ {
+ //parent::__construct();
+ $this->_writers = $writers;
+ }
+
+ public function write($s)
+ {
+ foreach($this->_writers as $writer)
+ $writer->write($s);
+ }
+
+ public function flush()
+ {
+ foreach($this->_writers as $writer)
+ $s = $writer->flush();
+ return $s;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TPager.php b/framework/Web/UI/WebControls/TPager.php
index 8e4bf2b0..11de5233 100644
--- a/framework/Web/UI/WebControls/TPager.php
+++ b/framework/Web/UI/WebControls/TPager.php
@@ -1,792 +1,792 @@
-<?php
-/**
- * TPager class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TPager class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TPager class.
- *
- * TPager creates a pager that provides UI for end-users to interactively
- * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control,
- * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc.
- * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate},
- * which must be the ID path of the target control reaching from the pager's
- * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging}
- * set to true.
- *
- * TPager can display three different UIs, specified via {@link setMode Mode}:
- * - NextPrev: a next page and a previous page button are rendered.
- * - Numeric: a list of page index buttons are rendered.
- * - List: a dropdown list of page indices are rendered.
- *
- * When the pager mode is either NextPrev or Numeric, the paging buttons may be displayed
- * in three types by setting {@link setButtonType ButtonType}:
- * - LinkButton: a hyperlink button
- * - PushButton: a normal button
- * - ImageButton: an image button (please set XXXPageImageUrl properties accordingly to specify the button images.)
- *
- * TPager raises an {@link onPageIndexChanged OnPageIndexChanged} event when
- * the end-user interacts with it and specifies a new page (e.g. clicking
- * on a page button that leads to a new page.) The new page index may be obtained
- * from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}.
- * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex}
- * to this new page index so that the new page of data is rendered.
- *
- * Multiple pagers can be associated with the same data-bound control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.2
- */
-class TPager extends TWebControl implements INamingContainer
-{
- /**
- * Command name that TPager understands.
- */
- const CMD_PAGE='Page';
- const CMD_PAGE_NEXT='Next';
- const CMD_PAGE_PREV='Previous';
- const CMD_PAGE_FIRST='First';
- const CMD_PAGE_LAST='Last';
-
- private $_pageCount=0;
-
- /**
- * Restores the pager state.
- * This method overrides the parent implementation and is invoked when
- * the control is loading persistent state.
- */
- public function loadState()
- {
- parent::loadState();
- if($this->getEnableViewState(true))
- {
- $this->getControls()->clear();
- $this->buildPager();
- }
- }
-
- /**
- * @return string the ID path of the control whose content would be paginated.
- */
- public function getControlToPaginate()
- {
- return $this->getViewState('ControlToPaginate','');
- }
-
- /**
- * Sets the ID path of the control whose content would be paginated.
- * The ID path is the dot-connected IDs of the controls reaching from
- * the pager's naming container to the target control.
- * @param string the ID path
- */
- public function setControlToPaginate($value)
- {
- $this->setViewState('ControlToPaginate',$value,'');
- }
-
- /**
- * @return TPagerMode pager mode. Defaults to TPagerMode::NextPrev.
- */
- public function getMode()
- {
- return $this->getViewState('Mode',TPagerMode::NextPrev);
- }
-
- /**
- * @param TPagerMode pager mode.
- */
- public function setMode($value)
- {
- $this->setViewState('Mode',TPropertyValue::ensureEnum($value,'TPagerMode'),TPagerMode::NextPrev);
- }
-
- /**
- * @return TPagerButtonType the type of command button for paging. Defaults to TPagerButtonType::LinkButton.
- */
- public function getButtonType()
- {
- return $this->getViewState('ButtonType',TPagerButtonType::LinkButton);
- }
-
- /**
- * @param TPagerButtonType the type of command button for paging.
- */
- public function setButtonType($value)
- {
- $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TPagerButtonType'),TPagerButtonType::LinkButton);
- }
-
- /**
- * @return string text for the next page button. Defaults to '>'.
- */
- public function getNextPageText()
- {
- return $this->getViewState('NextPageText','>');
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setNextPageText($value)
- {
- $this->setViewState('NextPageText',$value,'>');
- }
-
- /**
- * @return string text for the previous page button. Defaults to '<'.
- */
- public function getPrevPageText()
- {
- return $this->getViewState('PrevPageText','<');
- }
-
- /**
- * @param string text for the next page button.
- */
- public function setPrevPageText($value)
- {
- $this->setViewState('PrevPageText',$value,'<');
- }
-
- /**
- * @return string text for the first page button. Defaults to '<<'.
- */
- public function getFirstPageText()
- {
- return $this->getViewState('FirstPageText','<<');
- }
-
- /**
- * @param string text for the first page button. If empty, the first page button will not be rendered.
- */
- public function setFirstPageText($value)
- {
- $this->setViewState('FirstPageText',$value,'<<');
- }
-
- /**
- * @return string text for the last page button. Defaults to '>>'.
- */
- public function getLastPageText()
- {
- return $this->getViewState('LastPageText','>>');
- }
-
- /**
- * @param string text for the last page button. If empty, the last page button will not be rendered.
- */
- public function setLastPageText($value)
- {
- $this->setViewState('LastPageText',$value,'>>');
- }
-
- /**
- * @return string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getFirstPageImageUrl()
- {
- return $this->getViewState('FirstPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setFirstPageImageUrl($value)
- {
- $this->setViewState('FirstPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getLastPageImageUrl()
- {
- return $this->getViewState('LastPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setLastPageImageUrl($value)
- {
- $this->setViewState('LastPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getNextPageImageUrl()
- {
- return $this->getViewState('NextPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setNextPageImageUrl($value)
- {
- $this->setViewState('NextPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function getPrevPageImageUrl()
- {
- return $this->getViewState('PrevPageImageUrl','');
- }
-
- /**
- * @param string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
- * @since 3.1.1
- */
- public function setPrevPageImageUrl($value)
- {
- $this->setViewState('PrevPageImageUrl',$value);
- }
-
- /**
- * @return string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
- * @see setNumericPageImageUrl
- * @since 3.1.1
- */
- public function getNumericPageImageUrl()
- {
- return $this->getViewState('NumericPageImageUrl','');
- }
-
- /**
- * Sets the image URL for the numeric page buttons.
- * This is actually a template for generating a set of URLs corresponding to numeric button 1, 2, 3, .., etc.
- * Use {0} as the placeholder for the numbers.
- * For example, the image URL http://example.com/images/button{0}.gif
- * will be replaced as http://example.com/images/button1.gif, http://example.com/images/button2.gif, etc.
- * @param string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
- * @since 3.1.1
- */
- public function setNumericPageImageUrl($value)
- {
- $this->setViewState('NumericPageImageUrl',$value);
- }
-
- /**
- * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
- */
- public function getPageButtonCount()
- {
- return $this->getViewState('PageButtonCount',10);
- }
-
- /**
- * @param integer maximum number of pager buttons to be displayed
- * @throws TInvalidDataValueException if the value is less than 1.
- */
- public function setPageButtonCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('pager_pagebuttoncount_invalid');
- $this->setViewState('PageButtonCount',$value,10);
- }
-
- /**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- protected function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_currentpageindex_invalid');
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer number of pages of data items available
- */
- public function getPageCount()
- {
- return $this->getViewState('PageCount',0);
- }
-
- /**
- * @param integer number of pages of data items available
- * @throws TInvalidDataValueException if the value is less than 0
- */
- protected function setPageCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_pagecount_invalid');
- $this->setViewState('PageCount',$value,0);
- }
-
- /**
- * @return boolean whether the current page is the first page Defaults to false.
- */
- public function getIsFirstPage()
- {
- return $this->getCurrentPageIndex()===0;
- }
-
- /**
- * @return boolean whether the current page is the last page
- */
- public function getIsLastPage()
- {
- return $this->getCurrentPageIndex()===$this->getPageCount()-1;
- }
-
- /**
- * Performs databinding to populate data items from data source.
- * This method is invoked by {@link dataBind()}.
- * You may override this function to provide your own way of data population.
- * @param Traversable the bound data
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- $controlID=$this->getControlToPaginate();
- if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl))
- throw new TConfigurationException('pager_controltopaginate_invalid',$controlID);
-
- if($targetControl->getAllowPaging())
- {
- $this->_pageCount=$targetControl->getPageCount();
- $this->getControls()->clear();
- $this->setPageCount($targetControl->getPageCount());
- $this->setCurrentPageIndex($targetControl->getCurrentPageIndex());
- $this->buildPager();
- }
- else
- $this->_pageCount=0;
- }
-
- /**
- * Renders the control.
- * The method overrides the parent implementation by rendering
- * the pager only when there are two or more pages.
- * @param THtmlWriter the writer
- */
- public function render($writer)
- {
- if($this->_pageCount>1)
- parent::render($writer);
- }
-
- /**
- * Builds the pager content based on the pager mode.
- * Current implementation includes building 'NextPrev', 'Numeric' and 'DropDownList' pagers.
- * Derived classes may override this method to provide additional pagers.
- */
- protected function buildPager()
- {
- switch($this->getMode())
- {
- case TPagerMode::NextPrev:
- $this->buildNextPrevPager();
- break;
- case TPagerMode::Numeric:
- $this->buildNumericPager();
- break;
- case TPagerMode::DropDownList:
- $this->buildListPager();
- break;
- }
- }
-
- /**
- * Creates a pager button.
- * Depending on the button type, a TLinkButton or a TButton may be created.
- * If it is enabled (clickable), its command name and parameter will also be set.
- * Derived classes may override this method to create additional types of buttons, such as TImageButton.
- * @param string button type, either LinkButton or PushButton
- * @param boolean whether the button should be enabled
- * @param string caption of the button.
- * @param string CommandName corresponding to the OnCommand event of the button.
- * @param string CommandParameter corresponding to the OnCommand event of the button
- * @return mixed the button instance
- */
- protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
- {
- if($buttonType===TPagerButtonType::LinkButton)
- {
- if($enabled)
- $button=new TLinkButton;
- else
- {
- $button=new TLabel;
- $button->setText($text);
- return $button;
- }
- }
- else
- {
- if($buttonType===TPagerButtonType::ImageButton)
- {
- $button=new TImageButton;
- $button->setImageUrl($this->getPageImageUrl($text,$commandName));
- }
- else
- $button=new TButton;
- if(!$enabled)
- $button->setEnabled(false);
- }
- $button->setText($text);
- $button->setCommandName($commandName);
- $button->setCommandParameter($commandParameter);
- $button->setCausesValidation(false);
- return $button;
- }
-
- /**
- * @param string the caption of the image button
- * @param string the command name associated with the image button
- * @since 3.1.1
- */
- protected function getPageImageUrl($text,$commandName)
- {
- switch($commandName)
- {
- case self::CMD_PAGE:
- $url=$this->getNumericPageImageUrl();
- return str_replace('{0}',$text,$url);
- case self::CMD_PAGE_NEXT:
- return $this->getNextPageImageUrl();
- case self::CMD_PAGE_PREV:
- return $this->getPrevPageImageUrl();
- case self::CMD_PAGE_FIRST:
- return $this->getFirstPageImageUrl();
- case self::CMD_PAGE_LAST:
- return $this->getLastPageImageUrl();
- default:
- return '';
- }
- }
-
- /**
- * Builds a next-prev pager
- */
- protected function buildNextPrevPager()
- {
- $buttonType=$this->getButtonType();
- $controls=$this->getControls();
- if($this->getIsFirstPage())
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($label);
- $controls->add("\n");
- }
- $label=$this->createPagerButton($buttonType,false,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
- $controls->add($label);
- }
- else
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($button);
- $controls->add("\n");
- }
- $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
- $controls->add($button);
- }
- $controls->add("\n");
- if($this->getIsLastPage())
- {
- $label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
- $controls->add($label);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_LAST,'');
- $controls->add($label);
- }
- }
- else
- {
- $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
- $controls->add($button);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a numeric pager
- */
- protected function buildNumericPager()
- {
- $buttonType=$this->getButtonType();
- $controls=$this->getControls();
- $pageCount=$this->getPageCount();
- $pageIndex=$this->getCurrentPageIndex()+1;
- $maxButtonCount=$this->getPageButtonCount();
- $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
- $startPageIndex=1;
- $endPageIndex=$buttonCount;
- if($pageIndex>$endPageIndex)
- {
- $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
- if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
- $endPageIndex=$pageCount;
- if($endPageIndex-$startPageIndex+1<$maxButtonCount)
- {
- if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
- $startPageIndex=1;
- }
- }
-
- if($startPageIndex>1)
- {
- if(($text=$this->getFirstPageText())!=='')
- {
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
- $controls->add($button);
- $controls->add("\n");
- }
- $prevPageIndex=$startPageIndex-1;
- $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
- $controls->add($button);
- $controls->add("\n");
- }
-
- for($i=$startPageIndex;$i<=$endPageIndex;++$i)
- {
- if($i===$pageIndex)
- {
- $label=$this->createPagerButton($buttonType,false,"$i",self::CMD_PAGE,'');
- $controls->add($label);
- }
- else
- {
- $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
- $controls->add($button);
- }
- if($i<$endPageIndex)
- $controls->add("\n");
- }
-
- if($pageCount>$endPageIndex)
- {
- $controls->add("\n");
- $nextPageIndex=$endPageIndex+1;
- $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
- $controls->add($button);
- if(($text=$this->getLastPageText())!=='')
- {
- $controls->add("\n");
- $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
- $controls->add($button);
- }
- }
- }
-
- /**
- * Builds a dropdown list pager
- */
- protected function buildListPager()
- {
- $list=new TDropDownList;
- $this->getControls()->add($list);
- $list->setDataSource(range(1,$this->getPageCount()));
- $list->dataBind();
- $list->setSelectedIndex($this->getCurrentPageIndex());
- $list->setAutoPostBack(true);
- $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
- }
-
- /**
- * Event handler to the OnSelectedIndexChanged event of the dropdown list.
- * This handler will raise {@link onPageIndexChanged OnPageIndexChanged} event.
- * @param TDropDownList the dropdown list control raising the event
- * @param TEventParameter event parameter
- */
- public function listIndexChanged($sender,$param)
- {
- $pageIndex=$sender->getSelectedIndex();
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- }
-
- /**
- * This event is raised when page index is changed due to a page button click.
- * @param TPagerPageChangedEventParameter event parameter
- */
- public function onPageIndexChanged($param)
- {
- $this->raiseEvent('OnPageIndexChanged',$this,$param);
- }
-
- /**
- * Processes a bubbled event.
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_PAGE)===0)
- {
- $pageIndex=TPropertyValue::ensureInteger($param->getCommandParameter())-1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_NEXT)===0)
- {
- $pageIndex=$this->getCurrentPageIndex()+1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_PREV)===0)
- {
- $pageIndex=$this->getCurrentPageIndex()-1;
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_FIRST)===0)
- {
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,0));
- return true;
- }
- else if(strcasecmp($command,self::CMD_PAGE_LAST)===0)
- {
- $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$this->getPageCount()-1));
- return true;
- }
- return false;
- }
- else
- return false;
- }
-}
-
-/**
- * TPagerPageChangedEventParameter class
- *
- * TPagerPageChangedEventParameter encapsulates the parameter data for
- * {@link TPager::onPageIndexChanged PageIndexChanged} event of {@link TPager} controls.
- *
- * The {@link getCommandSource CommandSource} property refers to the control
- * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
- * returns the new page index carried with the page command.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.2
- */
-class TPagerPageChangedEventParameter extends TEventParameter
-{
- /**
- * @var integer new page index
- */
- private $_newIndex;
- /**
- * @var TControl original event sender
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl the control originally raises the <b>OnCommand</b> event.
- * @param integer new page index
- */
- public function __construct($source,$newPageIndex)
- {
- $this->_source=$source;
- $this->_newIndex=$newPageIndex;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-
- /**
- * @return integer new page index
- */
- public function getNewPageIndex()
- {
- return $this->_newIndex;
- }
-}
-
-
-/**
- * TPagerMode class.
- * TPagerMode defines the enumerable type for the possible modes that a {@link TPager} control can take.
- *
- * The following enumerable values are defined:
- * - NextPrev: pager buttons are displayed as next and previous pages
- * - Numeric: pager buttons are displayed as numeric page numbers
- * - DropDownList: a dropdown list is used to select pages
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TPagerMode extends TEnumerable
-{
- const NextPrev='NextPrev';
- const Numeric='Numeric';
- const DropDownList='DropDownList';
-}
-
-
-/**
- * TPagerButtonType class.
- * TPagerButtonType defines the enumerable type for the possible types of pager buttons.
- *
- * The following enumerable values are defined:
- * - LinkButton: link buttons
- * - PushButton: form submit buttons
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TPagerButtonType extends TEnumerable
-{
- const LinkButton='LinkButton';
- const PushButton='PushButton';
- const ImageButton='ImageButton';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TPager class.
+ *
+ * TPager creates a pager that provides UI for end-users to interactively
+ * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control,
+ * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc.
+ * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate},
+ * which must be the ID path of the target control reaching from the pager's
+ * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging}
+ * set to true.
+ *
+ * TPager can display three different UIs, specified via {@link setMode Mode}:
+ * - NextPrev: a next page and a previous page button are rendered.
+ * - Numeric: a list of page index buttons are rendered.
+ * - List: a dropdown list of page indices are rendered.
+ *
+ * When the pager mode is either NextPrev or Numeric, the paging buttons may be displayed
+ * in three types by setting {@link setButtonType ButtonType}:
+ * - LinkButton: a hyperlink button
+ * - PushButton: a normal button
+ * - ImageButton: an image button (please set XXXPageImageUrl properties accordingly to specify the button images.)
+ *
+ * TPager raises an {@link onPageIndexChanged OnPageIndexChanged} event when
+ * the end-user interacts with it and specifies a new page (e.g. clicking
+ * on a page button that leads to a new page.) The new page index may be obtained
+ * from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}.
+ * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex}
+ * to this new page index so that the new page of data is rendered.
+ *
+ * Multiple pagers can be associated with the same data-bound control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.2
+ */
+class TPager extends TWebControl implements INamingContainer
+{
+ /**
+ * Command name that TPager understands.
+ */
+ const CMD_PAGE='Page';
+ const CMD_PAGE_NEXT='Next';
+ const CMD_PAGE_PREV='Previous';
+ const CMD_PAGE_FIRST='First';
+ const CMD_PAGE_LAST='Last';
+
+ private $_pageCount=0;
+
+ /**
+ * Restores the pager state.
+ * This method overrides the parent implementation and is invoked when
+ * the control is loading persistent state.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if($this->getEnableViewState(true))
+ {
+ $this->getControls()->clear();
+ $this->buildPager();
+ }
+ }
+
+ /**
+ * @return string the ID path of the control whose content would be paginated.
+ */
+ public function getControlToPaginate()
+ {
+ return $this->getViewState('ControlToPaginate','');
+ }
+
+ /**
+ * Sets the ID path of the control whose content would be paginated.
+ * The ID path is the dot-connected IDs of the controls reaching from
+ * the pager's naming container to the target control.
+ * @param string the ID path
+ */
+ public function setControlToPaginate($value)
+ {
+ $this->setViewState('ControlToPaginate',$value,'');
+ }
+
+ /**
+ * @return TPagerMode pager mode. Defaults to TPagerMode::NextPrev.
+ */
+ public function getMode()
+ {
+ return $this->getViewState('Mode',TPagerMode::NextPrev);
+ }
+
+ /**
+ * @param TPagerMode pager mode.
+ */
+ public function setMode($value)
+ {
+ $this->setViewState('Mode',TPropertyValue::ensureEnum($value,'TPagerMode'),TPagerMode::NextPrev);
+ }
+
+ /**
+ * @return TPagerButtonType the type of command button for paging. Defaults to TPagerButtonType::LinkButton.
+ */
+ public function getButtonType()
+ {
+ return $this->getViewState('ButtonType',TPagerButtonType::LinkButton);
+ }
+
+ /**
+ * @param TPagerButtonType the type of command button for paging.
+ */
+ public function setButtonType($value)
+ {
+ $this->setViewState('ButtonType',TPropertyValue::ensureEnum($value,'TPagerButtonType'),TPagerButtonType::LinkButton);
+ }
+
+ /**
+ * @return string text for the next page button. Defaults to '>'.
+ */
+ public function getNextPageText()
+ {
+ return $this->getViewState('NextPageText','>');
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setNextPageText($value)
+ {
+ $this->setViewState('NextPageText',$value,'>');
+ }
+
+ /**
+ * @return string text for the previous page button. Defaults to '<'.
+ */
+ public function getPrevPageText()
+ {
+ return $this->getViewState('PrevPageText','<');
+ }
+
+ /**
+ * @param string text for the next page button.
+ */
+ public function setPrevPageText($value)
+ {
+ $this->setViewState('PrevPageText',$value,'<');
+ }
+
+ /**
+ * @return string text for the first page button. Defaults to '<<'.
+ */
+ public function getFirstPageText()
+ {
+ return $this->getViewState('FirstPageText','<<');
+ }
+
+ /**
+ * @param string text for the first page button. If empty, the first page button will not be rendered.
+ */
+ public function setFirstPageText($value)
+ {
+ $this->setViewState('FirstPageText',$value,'<<');
+ }
+
+ /**
+ * @return string text for the last page button. Defaults to '>>'.
+ */
+ public function getLastPageText()
+ {
+ return $this->getViewState('LastPageText','>>');
+ }
+
+ /**
+ * @param string text for the last page button. If empty, the last page button will not be rendered.
+ */
+ public function setLastPageText($value)
+ {
+ $this->setViewState('LastPageText',$value,'>>');
+ }
+
+ /**
+ * @return string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getFirstPageImageUrl()
+ {
+ return $this->getViewState('FirstPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the first page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setFirstPageImageUrl($value)
+ {
+ $this->setViewState('FirstPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getLastPageImageUrl()
+ {
+ return $this->getViewState('LastPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the last page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setLastPageImageUrl($value)
+ {
+ $this->setViewState('LastPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getNextPageImageUrl()
+ {
+ return $this->getViewState('NextPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the next page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setNextPageImageUrl($value)
+ {
+ $this->setViewState('NextPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function getPrevPageImageUrl()
+ {
+ return $this->getViewState('PrevPageImageUrl','');
+ }
+
+ /**
+ * @param string the image URL for the previous page button. This is only used when {@link getButtonType ButtonType} is 'ImageButton'.
+ * @since 3.1.1
+ */
+ public function setPrevPageImageUrl($value)
+ {
+ $this->setViewState('PrevPageImageUrl',$value);
+ }
+
+ /**
+ * @return string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
+ * @see setNumericPageImageUrl
+ * @since 3.1.1
+ */
+ public function getNumericPageImageUrl()
+ {
+ return $this->getViewState('NumericPageImageUrl','');
+ }
+
+ /**
+ * Sets the image URL for the numeric page buttons.
+ * This is actually a template for generating a set of URLs corresponding to numeric button 1, 2, 3, .., etc.
+ * Use {0} as the placeholder for the numbers.
+ * For example, the image URL http://example.com/images/button{0}.gif
+ * will be replaced as http://example.com/images/button1.gif, http://example.com/images/button2.gif, etc.
+ * @param string the image URL for the numeric page buttons. This is only used when {@link getButtonType ButtonType} is 'ImageButton' and {@link getMode Mode} is 'Numeric'.
+ * @since 3.1.1
+ */
+ public function setNumericPageImageUrl($value)
+ {
+ $this->setViewState('NumericPageImageUrl',$value);
+ }
+
+ /**
+ * @return integer maximum number of pager buttons to be displayed. Defaults to 10.
+ */
+ public function getPageButtonCount()
+ {
+ return $this->getViewState('PageButtonCount',10);
+ }
+
+ /**
+ * @param integer maximum number of pager buttons to be displayed
+ * @throws TInvalidDataValueException if the value is less than 1.
+ */
+ public function setPageButtonCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('pager_pagebuttoncount_invalid');
+ $this->setViewState('PageButtonCount',$value,10);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ protected function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_currentpageindex_invalid');
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',0);
+ }
+
+ /**
+ * @param integer number of pages of data items available
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ protected function setPageCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_pagecount_invalid');
+ $this->setViewState('PageCount',$value,0);
+ }
+
+ /**
+ * @return boolean whether the current page is the first page Defaults to false.
+ */
+ public function getIsFirstPage()
+ {
+ return $this->getCurrentPageIndex()===0;
+ }
+
+ /**
+ * @return boolean whether the current page is the last page
+ */
+ public function getIsLastPage()
+ {
+ return $this->getCurrentPageIndex()===$this->getPageCount()-1;
+ }
+
+ /**
+ * Performs databinding to populate data items from data source.
+ * This method is invoked by {@link dataBind()}.
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the bound data
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ $controlID=$this->getControlToPaginate();
+ if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl))
+ throw new TConfigurationException('pager_controltopaginate_invalid',$controlID);
+
+ if($targetControl->getAllowPaging())
+ {
+ $this->_pageCount=$targetControl->getPageCount();
+ $this->getControls()->clear();
+ $this->setPageCount($targetControl->getPageCount());
+ $this->setCurrentPageIndex($targetControl->getCurrentPageIndex());
+ $this->buildPager();
+ }
+ else
+ $this->_pageCount=0;
+ }
+
+ /**
+ * Renders the control.
+ * The method overrides the parent implementation by rendering
+ * the pager only when there are two or more pages.
+ * @param THtmlWriter the writer
+ */
+ public function render($writer)
+ {
+ if($this->_pageCount>1)
+ parent::render($writer);
+ }
+
+ /**
+ * Builds the pager content based on the pager mode.
+ * Current implementation includes building 'NextPrev', 'Numeric' and 'DropDownList' pagers.
+ * Derived classes may override this method to provide additional pagers.
+ */
+ protected function buildPager()
+ {
+ switch($this->getMode())
+ {
+ case TPagerMode::NextPrev:
+ $this->buildNextPrevPager();
+ break;
+ case TPagerMode::Numeric:
+ $this->buildNumericPager();
+ break;
+ case TPagerMode::DropDownList:
+ $this->buildListPager();
+ break;
+ }
+ }
+
+ /**
+ * Creates a pager button.
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param string button type, either LinkButton or PushButton
+ * @param boolean whether the button should be enabled
+ * @param string caption of the button.
+ * @param string CommandName corresponding to the OnCommand event of the button.
+ * @param string CommandParameter corresponding to the OnCommand event of the button
+ * @return mixed the button instance
+ */
+ protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
+ {
+ if($buttonType===TPagerButtonType::LinkButton)
+ {
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
+ }
+ else
+ {
+ if($buttonType===TPagerButtonType::ImageButton)
+ {
+ $button=new TImageButton;
+ $button->setImageUrl($this->getPageImageUrl($text,$commandName));
+ }
+ else
+ $button=new TButton;
+ if(!$enabled)
+ $button->setEnabled(false);
+ }
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ return $button;
+ }
+
+ /**
+ * @param string the caption of the image button
+ * @param string the command name associated with the image button
+ * @since 3.1.1
+ */
+ protected function getPageImageUrl($text,$commandName)
+ {
+ switch($commandName)
+ {
+ case self::CMD_PAGE:
+ $url=$this->getNumericPageImageUrl();
+ return str_replace('{0}',$text,$url);
+ case self::CMD_PAGE_NEXT:
+ return $this->getNextPageImageUrl();
+ case self::CMD_PAGE_PREV:
+ return $this->getPrevPageImageUrl();
+ case self::CMD_PAGE_FIRST:
+ return $this->getFirstPageImageUrl();
+ case self::CMD_PAGE_LAST:
+ return $this->getLastPageImageUrl();
+ default:
+ return '';
+ }
+ }
+
+ /**
+ * Builds a next-prev pager
+ */
+ protected function buildNextPrevPager()
+ {
+ $buttonType=$this->getButtonType();
+ $controls=$this->getControls();
+ if($this->getIsFirstPage())
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($label);
+ $controls->add("\n");
+ }
+ $label=$this->createPagerButton($buttonType,false,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
+ $controls->add($label);
+ }
+ else
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE_PREV,'');
+ $controls->add($button);
+ }
+ $controls->add("\n");
+ if($this->getIsLastPage())
+ {
+ $label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
+ $controls->add($label);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $label=$this->createPagerButton($buttonType,false,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($label);
+ }
+ }
+ else
+ {
+ $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE_NEXT,'');
+ $controls->add($button);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a numeric pager
+ */
+ protected function buildNumericPager()
+ {
+ $buttonType=$this->getButtonType();
+ $controls=$this->getControls();
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $maxButtonCount=$this->getPageButtonCount();
+ $buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
+ $startPageIndex=1;
+ $endPageIndex=$buttonCount;
+ if($pageIndex>$endPageIndex)
+ {
+ $startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
+ if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
+ $endPageIndex=$pageCount;
+ if($endPageIndex-$startPageIndex+1<$maxButtonCount)
+ {
+ if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
+ $startPageIndex=1;
+ }
+ }
+
+ if($startPageIndex>1)
+ {
+ if(($text=$this->getFirstPageText())!=='')
+ {
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_FIRST,'');
+ $controls->add($button);
+ $controls->add("\n");
+ }
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($buttonType,true,$this->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
+ $controls->add($button);
+ $controls->add("\n");
+ }
+
+ for($i=$startPageIndex;$i<=$endPageIndex;++$i)
+ {
+ if($i===$pageIndex)
+ {
+ $label=$this->createPagerButton($buttonType,false,"$i",self::CMD_PAGE,'');
+ $controls->add($label);
+ }
+ else
+ {
+ $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
+ $controls->add($button);
+ }
+ if($i<$endPageIndex)
+ $controls->add("\n");
+ }
+
+ if($pageCount>$endPageIndex)
+ {
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($buttonType,true,$this->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
+ $controls->add($button);
+ if(($text=$this->getLastPageText())!=='')
+ {
+ $controls->add("\n");
+ $button=$this->createPagerButton($buttonType,true,$text,self::CMD_PAGE_LAST,'');
+ $controls->add($button);
+ }
+ }
+ }
+
+ /**
+ * Builds a dropdown list pager
+ */
+ protected function buildListPager()
+ {
+ $list=new TDropDownList;
+ $this->getControls()->add($list);
+ $list->setDataSource(range(1,$this->getPageCount()));
+ $list->dataBind();
+ $list->setSelectedIndex($this->getCurrentPageIndex());
+ $list->setAutoPostBack(true);
+ $list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
+ }
+
+ /**
+ * Event handler to the OnSelectedIndexChanged event of the dropdown list.
+ * This handler will raise {@link onPageIndexChanged OnPageIndexChanged} event.
+ * @param TDropDownList the dropdown list control raising the event
+ * @param TEventParameter event parameter
+ */
+ public function listIndexChanged($sender,$param)
+ {
+ $pageIndex=$sender->getSelectedIndex();
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ }
+
+ /**
+ * This event is raised when page index is changed due to a page button click.
+ * @param TPagerPageChangedEventParameter event parameter
+ */
+ public function onPageIndexChanged($param)
+ {
+ $this->raiseEvent('OnPageIndexChanged',$this,$param);
+ }
+
+ /**
+ * Processes a bubbled event.
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_PAGE)===0)
+ {
+ $pageIndex=TPropertyValue::ensureInteger($param->getCommandParameter())-1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_NEXT)===0)
+ {
+ $pageIndex=$this->getCurrentPageIndex()+1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_PREV)===0)
+ {
+ $pageIndex=$this->getCurrentPageIndex()-1;
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$pageIndex));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_FIRST)===0)
+ {
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,0));
+ return true;
+ }
+ else if(strcasecmp($command,self::CMD_PAGE_LAST)===0)
+ {
+ $this->onPageIndexChanged(new TPagerPageChangedEventParameter($sender,$this->getPageCount()-1));
+ return true;
+ }
+ return false;
+ }
+ else
+ return false;
+ }
+}
+
+/**
+ * TPagerPageChangedEventParameter class
+ *
+ * TPagerPageChangedEventParameter encapsulates the parameter data for
+ * {@link TPager::onPageIndexChanged PageIndexChanged} event of {@link TPager} controls.
+ *
+ * The {@link getCommandSource CommandSource} property refers to the control
+ * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
+ * returns the new page index carried with the page command.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.2
+ */
+class TPagerPageChangedEventParameter extends TEventParameter
+{
+ /**
+ * @var integer new page index
+ */
+ private $_newIndex;
+ /**
+ * @var TControl original event sender
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl the control originally raises the <b>OnCommand</b> event.
+ * @param integer new page index
+ */
+ public function __construct($source,$newPageIndex)
+ {
+ $this->_source=$source;
+ $this->_newIndex=$newPageIndex;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+
+ /**
+ * @return integer new page index
+ */
+ public function getNewPageIndex()
+ {
+ return $this->_newIndex;
+ }
+}
+
+
+/**
+ * TPagerMode class.
+ * TPagerMode defines the enumerable type for the possible modes that a {@link TPager} control can take.
+ *
+ * The following enumerable values are defined:
+ * - NextPrev: pager buttons are displayed as next and previous pages
+ * - Numeric: pager buttons are displayed as numeric page numbers
+ * - DropDownList: a dropdown list is used to select pages
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TPagerMode extends TEnumerable
+{
+ const NextPrev='NextPrev';
+ const Numeric='Numeric';
+ const DropDownList='DropDownList';
+}
+
+
+/**
+ * TPagerButtonType class.
+ * TPagerButtonType defines the enumerable type for the possible types of pager buttons.
+ *
+ * The following enumerable values are defined:
+ * - LinkButton: link buttons
+ * - PushButton: form submit buttons
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TPagerButtonType extends TEnumerable
+{
+ const LinkButton='LinkButton';
+ const PushButton='PushButton';
+ const ImageButton='ImageButton';
+}
+
diff --git a/framework/Web/UI/WebControls/TPanel.php b/framework/Web/UI/WebControls/TPanel.php
index 5d651679..d4e05136 100644
--- a/framework/Web/UI/WebControls/TPanel.php
+++ b/framework/Web/UI/WebControls/TPanel.php
@@ -1,246 +1,246 @@
-<?php
-/**
- * TPanel class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TPanelStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TPanelStyle');
-
-/**
- * TPanel class
- *
- * TPanel represents a component that acts as a container for other component.
- * It is especially useful when you want to generate components programmatically
- * or hide/show a group of components.
- *
- * By default, TPanel displays a &lt;div&gt; element on a page.
- * Children of TPanel are displayed as the body content of the element.
- * The property {@link setWrap Wrap} can be used to set whether the body content
- * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
- * the content is aligned horizontally, and {@link getDirection Direction} indicates
- * the content direction (left to right or right to left). You can set
- * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
- * and you can ste {@link setGroupingText GroupingText} so that the panel is
- * displayed as a field set with a legend text. Finally, you can specify
- * a default button to be fired when users press 'return' key within the panel
- * by setting the {@link setDefaultButton DefaultButton} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPanel extends TWebControl
-{
- /**
- * @var string ID path to the default button
- */
- private $_defaultButton='';
-
- /**
- * @return string tag name of the panel
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Creates a style object to be used by the control.
- * This method overrides the parent impementation by creating a TPanelStyle object.
- * @return TPanelStyle the style used by TPanel.
- */
- protected function createStyle()
- {
- return new TPanelStyle;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- * @throws TInvalidDataValueException if default button is not right.
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($butt=$this->getDefaultButton())!=='')
- $writer->addAttribute('id',$this->getClientID());
- }
-
- /**
- * @return boolean whether the content wraps within the panel. Defaults to true.
- */
- public function getWrap()
- {
- return $this->getStyle()->getWrap();
- }
-
- /**
- * Sets the value indicating whether the content wraps within the panel.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->getStyle()->setWrap($value);
- }
-
- /**
- * @return string the horizontal alignment of the contents within the panel, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- return $this->getStyle()->getHorizontalAlign();
- }
-
- /**
- * Sets the horizontal alignment of the contents within the panel.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the URL of the background image for the panel component.
- */
- public function getBackImageUrl()
- {
- return $this->getStyle()->getBackImageUrl();
- }
-
- /**
- * Sets the URL of the background image for the panel component.
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * @return string alignment of the content in the panel. Defaults to 'NotSet'.
- */
- public function getDirection()
- {
- return $this->getStyle()->getDirection();
- }
-
- /**
- * @param string alignment of the content in the panel.
- * Valid values include 'NotSet', 'LeftToRight', 'RightToLeft'.
- */
- public function setDirection($value)
- {
- $this->getStyle()->setDirection($value);
- }
-
- /**
- * @return string the ID path to the default button. Defaults to empty.
- */
- public function getDefaultButton()
- {
- return $this->_defaultButton;
- }
-
- /**
- * Specifies the default button for the panel.
- * The default button will be fired (clicked) whenever a user enters 'return'
- * key within the panel.
- * The button must be locatable via the function call {@link TControl::findControl findControl}.
- * @param string the ID path to the default button.
- */
- public function setDefaultButton($value)
- {
- $this->_defaultButton=$value;
- }
-
- /**
- * @return string the legend text when the panel is used as a fieldset. Defaults to empty.
- */
- public function getGroupingText()
- {
- return $this->getViewState('GroupingText','');
- }
-
- /**
- * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset.
- */
- public function setGroupingText($value)
- {
- $this->setViewState('GroupingText',$value,'');
- }
-
- /**
- * @return string the visibility and position of scroll bars in a panel control, defaults to None.
- */
- public function getScrollBars()
- {
- return $this->getStyle()->getScrollBars();
- }
-
- /**
- * @param string the visibility and position of scroll bars in a panel control.
- * Valid values include None, Auto, Both, Horizontal and Vertical.
- */
- public function setScrollBars($value)
- {
- $this->getStyle()->setScrollBars($value);
- }
-
- /**
- * Renders the openning tag for the control (including attributes)
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($text=$this->getGroupingText())!=='')
- {
- $writer->renderBeginTag('fieldset');
- $writer->renderBeginTag('legend');
- $writer->write($text);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders the closing tag for the control
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- if($this->getGroupingText()!=='')
- $writer->renderEndTag();
- parent::renderEndTag($writer);
- }
-
- public function render($writer)
- {
- parent::render($writer);
-
- if(($butt=$this->getDefaultButton())!=='')
- {
- $buttons = $this->findControlsByID($butt);
- if (count($buttons)>0)
- $button = reset($buttons);
- else
- $button = null;
- if($button===null)
- throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt);
- else
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
- }
-}
-
+<?php
+/**
+ * TPanel class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TPanelStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TPanelStyle');
+
+/**
+ * TPanel class
+ *
+ * TPanel represents a component that acts as a container for other component.
+ * It is especially useful when you want to generate components programmatically
+ * or hide/show a group of components.
+ *
+ * By default, TPanel displays a &lt;div&gt; element on a page.
+ * Children of TPanel are displayed as the body content of the element.
+ * The property {@link setWrap Wrap} can be used to set whether the body content
+ * should wrap or not. {@link setHorizontalAlign HorizontalAlign} governs how
+ * the content is aligned horizontally, and {@link getDirection Direction} indicates
+ * the content direction (left to right or right to left). You can set
+ * {@link setBackImageUrl BackImageUrl} to give a background image to the panel,
+ * and you can ste {@link setGroupingText GroupingText} so that the panel is
+ * displayed as a field set with a legend text. Finally, you can specify
+ * a default button to be fired when users press 'return' key within the panel
+ * by setting the {@link setDefaultButton DefaultButton} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPanel extends TWebControl
+{
+ /**
+ * @var string ID path to the default button
+ */
+ private $_defaultButton='';
+
+ /**
+ * @return string tag name of the panel
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Creates a style object to be used by the control.
+ * This method overrides the parent impementation by creating a TPanelStyle object.
+ * @return TPanelStyle the style used by TPanel.
+ */
+ protected function createStyle()
+ {
+ return new TPanelStyle;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ * @throws TInvalidDataValueException if default button is not right.
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($butt=$this->getDefaultButton())!=='')
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ /**
+ * @return boolean whether the content wraps within the panel. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->getStyle()->getWrap();
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the panel.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->getStyle()->setWrap($value);
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the panel, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->getStyle()->getHorizontalAlign();
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the panel.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the URL of the background image for the panel component.
+ */
+ public function getBackImageUrl()
+ {
+ return $this->getStyle()->getBackImageUrl();
+ }
+
+ /**
+ * Sets the URL of the background image for the panel component.
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * @return string alignment of the content in the panel. Defaults to 'NotSet'.
+ */
+ public function getDirection()
+ {
+ return $this->getStyle()->getDirection();
+ }
+
+ /**
+ * @param string alignment of the content in the panel.
+ * Valid values include 'NotSet', 'LeftToRight', 'RightToLeft'.
+ */
+ public function setDirection($value)
+ {
+ $this->getStyle()->setDirection($value);
+ }
+
+ /**
+ * @return string the ID path to the default button. Defaults to empty.
+ */
+ public function getDefaultButton()
+ {
+ return $this->_defaultButton;
+ }
+
+ /**
+ * Specifies the default button for the panel.
+ * The default button will be fired (clicked) whenever a user enters 'return'
+ * key within the panel.
+ * The button must be locatable via the function call {@link TControl::findControl findControl}.
+ * @param string the ID path to the default button.
+ */
+ public function setDefaultButton($value)
+ {
+ $this->_defaultButton=$value;
+ }
+
+ /**
+ * @return string the legend text when the panel is used as a fieldset. Defaults to empty.
+ */
+ public function getGroupingText()
+ {
+ return $this->getViewState('GroupingText','');
+ }
+
+ /**
+ * @param string the legend text. If this value is not empty, the panel will be rendered as a fieldset.
+ */
+ public function setGroupingText($value)
+ {
+ $this->setViewState('GroupingText',$value,'');
+ }
+
+ /**
+ * @return string the visibility and position of scroll bars in a panel control, defaults to None.
+ */
+ public function getScrollBars()
+ {
+ return $this->getStyle()->getScrollBars();
+ }
+
+ /**
+ * @param string the visibility and position of scroll bars in a panel control.
+ * Valid values include None, Auto, Both, Horizontal and Vertical.
+ */
+ public function setScrollBars($value)
+ {
+ $this->getStyle()->setScrollBars($value);
+ }
+
+ /**
+ * Renders the openning tag for the control (including attributes)
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($text=$this->getGroupingText())!=='')
+ {
+ $writer->renderBeginTag('fieldset');
+ $writer->renderBeginTag('legend');
+ $writer->write($text);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders the closing tag for the control
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ if($this->getGroupingText()!=='')
+ $writer->renderEndTag();
+ parent::renderEndTag($writer);
+ }
+
+ public function render($writer)
+ {
+ parent::render($writer);
+
+ if(($butt=$this->getDefaultButton())!=='')
+ {
+ $buttons = $this->findControlsByID($butt);
+ if (count($buttons)>0)
+ $button = reset($buttons);
+ else
+ $button = null;
+ if($button===null)
+ throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt);
+ else
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TPanelStyle.php b/framework/Web/UI/WebControls/TPanelStyle.php
index 16169749..5e5db6e4 100644
--- a/framework/Web/UI/WebControls/TPanelStyle.php
+++ b/framework/Web/UI/WebControls/TPanelStyle.php
@@ -1,278 +1,278 @@
-<?php
-/**
- * TPanelStyle class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TPanelStyle class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TStyle');
-
-/**
- * TPanelStyle class.
- * TPanelStyle represents the CSS style specific for panel HTML tag.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPanelStyle extends TStyle
-{
- /**
- * @var string the URL of the background image for the panel component
- */
- private $_backImageUrl=null;
- /**
- * @var string alignment of the content in the panel.
- */
- private $_direction=null;
- /**
- * @var string horizontal alignment of the contents within the panel
- */
- private $_horizontalAlign=null;
- /**
- * @var string visibility and position of scroll bars
- */
- private $_scrollBars=null;
- /**
- * @var boolean whether the content wraps within the panel
- */
- private $_wrap=null;
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(($url=trim($this->getBackImageUrl()))!=='')
- $this->setStyleField('background-image','url('.$url.')');
-
- switch($this->getScrollBars())
- {
- case TScrollBars::Horizontal: $this->setStyleField('overflow-x','scroll'); break;
- case TScrollBars::Vertical: $this->setStyleField('overflow-y','scroll'); break;
- case TScrollBars::Both: $this->setStyleField('overflow','scroll'); break;
- case TScrollBars::Auto: $this->setStyleField('overflow','auto'); break;
- }
-
- if(($align=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $this->setStyleField('text-align',strtolower($align));
-
- if(!$this->getWrap())
- $this->setStyleField('white-space','nowrap');
-
- if(($direction=$this->getDirection())!==TContentDirection::NotSet)
- {
- if($direction===TContentDirection::LeftToRight)
- $this->setStyleField('direction','ltr');
- else
- $this->setStyleField('direction','rtl');
- }
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string the URL of the background image for the panel component.
- */
- public function getBackImageUrl()
- {
- return $this->_backImageUrl===null?'':$this->_backImageUrl;
- }
-
- /**
- * Sets the URL of the background image for the panel component.
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->_backImageUrl=$value;
- }
-
- /**
- * @return TContentDirection alignment of the content in the panel. Defaults to TContentDirection::NotSet.
- */
- public function getDirection()
- {
- return $this->_direction===null?TContentDirection::NotSet:$this->_direction;
- }
-
- /**
- * @param TContentDirection alignment of the content in the panel.
- */
- public function setDirection($value)
- {
- $this->_direction=TPropertyValue::ensureEnum($value,'TContentDirection');
- }
-
- /**
- * @return boolean whether the content wraps within the panel. Defaults to true.
- */
- public function getWrap()
- {
- return $this->_wrap===null?true:$this->_wrap;
- }
-
- /**
- * Sets the value indicating whether the content wraps within the panel.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->_wrap=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the panel, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the panel.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return TScrollBars the visibility and position of scroll bars in a panel control, defaults to TScrollBars::None.
- */
- public function getScrollBars()
- {
- return $this->_scrollBars===null?TScrollBars::None:$this->_scrollBars;
- }
-
- /**
- * @param TScrollBars the visibility and position of scroll bars in a panel control.
- */
- public function setScrollBars($value)
- {
- $this->_scrollBars=TPropertyValue::ensureEnum($value,'TScrollBars');
- }
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TPanelStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_backImageUrl=null;
- $this->_direction=null;
- $this->_horizontalAlign=null;
- $this->_scrollBars=null;
- $this->_wrap=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TPanelStyle)
- {
- if($style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($style->_direction!==null)
- $this->_direction=$style->_direction;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_scrollBars!==null)
- $this->_scrollBars=$style->_scrollBars;
- if($style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TPanelStyle)
- {
- if($this->_backImageUrl===null && $style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($this->_direction===null && $style->_direction!==null)
- $this->_direction=$style->_direction;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_scrollBars===null && $style->_scrollBars!==null)
- $this->_scrollBars=$style->_scrollBars;
- if($this->_wrap===null && $style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-}
-
-/**
- * TContentDirection class.
- * TContentDirection defines the enumerable type for the possible directions that a panel can be at.
- *
- * The following enumerable values are defined:
- * - NotSet: the direction is not specified
- * - LeftToRight: content in a panel is left to right
- * - RightToLeft: content in a panel is right to left
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TContentDirection extends TEnumerable
-{
- const NotSet='NotSet';
- const LeftToRight='LeftToRight';
- const RightToLeft='RightToLeft';
-}
-
-/**
- * TScrollBars class.
- * TScrollBars defines the enumerable type for the possible scroll bar mode
- * that a {@link TPanel} control could use.
- *
- * The following enumerable values are defined:
- * - None: no scroll bars.
- * - Auto: scroll bars automatically appeared when needed.
- * - Both: show both horizontal and vertical scroll bars all the time.
- * - Horizontal: horizontal scroll bar only
- * - Vertical: vertical scroll bar only
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TScrollBars extends TEnumerable
-{
- const None='None';
- const Auto='Auto';
- const Both='Both';
- const Horizontal='Horizontal';
- const Vertical='Vertical';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TStyle');
+
+/**
+ * TPanelStyle class.
+ * TPanelStyle represents the CSS style specific for panel HTML tag.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPanelStyle extends TStyle
+{
+ /**
+ * @var string the URL of the background image for the panel component
+ */
+ private $_backImageUrl=null;
+ /**
+ * @var string alignment of the content in the panel.
+ */
+ private $_direction=null;
+ /**
+ * @var string horizontal alignment of the contents within the panel
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var string visibility and position of scroll bars
+ */
+ private $_scrollBars=null;
+ /**
+ * @var boolean whether the content wraps within the panel
+ */
+ private $_wrap=null;
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(($url=trim($this->getBackImageUrl()))!=='')
+ $this->setStyleField('background-image','url('.$url.')');
+
+ switch($this->getScrollBars())
+ {
+ case TScrollBars::Horizontal: $this->setStyleField('overflow-x','scroll'); break;
+ case TScrollBars::Vertical: $this->setStyleField('overflow-y','scroll'); break;
+ case TScrollBars::Both: $this->setStyleField('overflow','scroll'); break;
+ case TScrollBars::Auto: $this->setStyleField('overflow','auto'); break;
+ }
+
+ if(($align=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $this->setStyleField('text-align',strtolower($align));
+
+ if(!$this->getWrap())
+ $this->setStyleField('white-space','nowrap');
+
+ if(($direction=$this->getDirection())!==TContentDirection::NotSet)
+ {
+ if($direction===TContentDirection::LeftToRight)
+ $this->setStyleField('direction','ltr');
+ else
+ $this->setStyleField('direction','rtl');
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string the URL of the background image for the panel component.
+ */
+ public function getBackImageUrl()
+ {
+ return $this->_backImageUrl===null?'':$this->_backImageUrl;
+ }
+
+ /**
+ * Sets the URL of the background image for the panel component.
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->_backImageUrl=$value;
+ }
+
+ /**
+ * @return TContentDirection alignment of the content in the panel. Defaults to TContentDirection::NotSet.
+ */
+ public function getDirection()
+ {
+ return $this->_direction===null?TContentDirection::NotSet:$this->_direction;
+ }
+
+ /**
+ * @param TContentDirection alignment of the content in the panel.
+ */
+ public function setDirection($value)
+ {
+ $this->_direction=TPropertyValue::ensureEnum($value,'TContentDirection');
+ }
+
+ /**
+ * @return boolean whether the content wraps within the panel. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->_wrap===null?true:$this->_wrap;
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the panel.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->_wrap=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the panel, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the panel.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return TScrollBars the visibility and position of scroll bars in a panel control, defaults to TScrollBars::None.
+ */
+ public function getScrollBars()
+ {
+ return $this->_scrollBars===null?TScrollBars::None:$this->_scrollBars;
+ }
+
+ /**
+ * @param TScrollBars the visibility and position of scroll bars in a panel control.
+ */
+ public function setScrollBars($value)
+ {
+ $this->_scrollBars=TPropertyValue::ensureEnum($value,'TScrollBars');
+ }
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TPanelStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_backImageUrl=null;
+ $this->_direction=null;
+ $this->_horizontalAlign=null;
+ $this->_scrollBars=null;
+ $this->_wrap=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TPanelStyle)
+ {
+ if($style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($style->_direction!==null)
+ $this->_direction=$style->_direction;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_scrollBars!==null)
+ $this->_scrollBars=$style->_scrollBars;
+ if($style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TPanelStyle)
+ {
+ if($this->_backImageUrl===null && $style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($this->_direction===null && $style->_direction!==null)
+ $this->_direction=$style->_direction;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_scrollBars===null && $style->_scrollBars!==null)
+ $this->_scrollBars=$style->_scrollBars;
+ if($this->_wrap===null && $style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+}
+
+/**
+ * TContentDirection class.
+ * TContentDirection defines the enumerable type for the possible directions that a panel can be at.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the direction is not specified
+ * - LeftToRight: content in a panel is left to right
+ * - RightToLeft: content in a panel is right to left
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TContentDirection extends TEnumerable
+{
+ const NotSet='NotSet';
+ const LeftToRight='LeftToRight';
+ const RightToLeft='RightToLeft';
+}
+
+/**
+ * TScrollBars class.
+ * TScrollBars defines the enumerable type for the possible scroll bar mode
+ * that a {@link TPanel} control could use.
+ *
+ * The following enumerable values are defined:
+ * - None: no scroll bars.
+ * - Auto: scroll bars automatically appeared when needed.
+ * - Both: show both horizontal and vertical scroll bars all the time.
+ * - Horizontal: horizontal scroll bar only
+ * - Vertical: vertical scroll bar only
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TScrollBars extends TEnumerable
+{
+ const None='None';
+ const Auto='Auto';
+ const Both='Both';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+}
+
diff --git a/framework/Web/UI/WebControls/TPlaceHolder.php b/framework/Web/UI/WebControls/TPlaceHolder.php
index ac67cef7..585e9e99 100644
--- a/framework/Web/UI/WebControls/TPlaceHolder.php
+++ b/framework/Web/UI/WebControls/TPlaceHolder.php
@@ -1,28 +1,28 @@
-<?php
-/**
- * TPlaceHolder class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TPlaceHolder class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TPlaceHolder class
- *
- * TPlaceHolder reserves a place on a template, where static texts or controls
- * may be inserted. You may add or remove texts or child controls of TPlaceHolder
- * by manipulating the {@link TControl::getControls Controls} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TPlaceHolder extends TControl
-{
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TPlaceHolder class
+ *
+ * TPlaceHolder reserves a place on a template, where static texts or controls
+ * may be inserted. You may add or remove texts or child controls of TPlaceHolder
+ * by manipulating the {@link TControl::getControls Controls} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TPlaceHolder extends TControl
+{
+}
+
diff --git a/framework/Web/UI/WebControls/TRadioButton.php b/framework/Web/UI/WebControls/TRadioButton.php
index b90cfcf5..6a2347f4 100644
--- a/framework/Web/UI/WebControls/TRadioButton.php
+++ b/framework/Web/UI/WebControls/TRadioButton.php
@@ -1,320 +1,320 @@
-<?php
-/**
- * TRadioButton class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TRadioButton class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TCheckBox parent class
- */
-Prado::using('System.Web.UI.WebControls.TCheckBox');
-/**
- * Using TRadioButtonList class
- */
-Prado::using('System.Web.UI.WebControls.TRadioButtonList');
-
-/**
- * TRadioButton class
- *
- * TRadioButton displays a radio button on the page.
- * You can specify the caption to display beside the radio buttonby setting
- * the {@link setText Text} property. The caption can appear either on the right
- * or left of the radio button, which is determined by the {@link setTextAlign TextAlign}
- * property.
- *
- * To determine whether the TRadioButton component is checked, test the {@link getChecked Checked}
- * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
- * the {@link getChecked Checked} state of the TRadioButton component changes
- * between posts to the server. You can provide an event handler for
- * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
- * control the actions performed when the state of the TRadioButton component changes
- * between posts to the server.
- *
- * TRadioButton uses {@link setGroupName GroupName} to group together a set of radio buttons.
- * Once the {@link setGroupName GroupName} is set, you can use the {@link getRadioButtonsInGroup}
- * method to get an array of TRadioButtons having the same group name.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, changing the radio button state
- * will cause postback action. And if {@link setCausesValidation CausesValidation}
- * is true, validation will also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
- * that may bring security vulnerabilities.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRadioButton extends TCheckBox
-{
- /**
- * @param array list of radio buttons that are on the current page hierarchy
- */
- private static $_activeButtons=array();
- /**
- * @var integer number of radio buttons created
- */
- private static $_buttonCount=0;
- /**
- * @var integer global ID of this radiobutton
- */
- private $_globalID;
- /**
- * @var string previous UniqueID (used to calculate UniqueGroup)
- */
- private $_previousUniqueID=null;
- /**
- * @var string the name used to fetch radiobutton post data
- */
- private $_uniqueGroupName=null;
-
- /**
- * Constructor.
- * Registers the radiobutton in a global radiobutton collection.
- * If overridden, the parent implementation must be invoked first.
- */
- public function __construct()
- {
- parent::__construct();
- $this->_globalID = self::$_buttonCount++;
- }
-
- /**
- * Registers the radio button groupings. If overriding onInit method,
- * ensure to call parent implemenation.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onInit($param)
- {
- parent::onInit($param);
- self::$_activeButtons[$this->_globalID]=$this;
- }
-
- /**
- * Unregisters the radio button groupings. If overriding onInit method,
- * ensure to call parent implemenation.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onUnLoad($param)
- {
- unset(self::$_activeButtons[$this->_globalID]);
- parent::onUnLoad($param);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the control has been changed
- */
- public function loadPostData($key,$values)
- {
- $uniqueGroupName=$this->getUniqueGroupName();
- $value=isset($values[$uniqueGroupName])?$values[$uniqueGroupName]:null;
- if($value!==null && $value===$this->getValueAttribute())
- {
- if(!$this->getChecked())
- {
- $this->setChecked(true);
- return true;
- }
- else
- return false;
- }
- else if($this->getChecked())
- $this->setChecked(false);
- return false;
- }
-
- /**
- * @return string the name of the group that the radio button belongs to. Defaults to empty.
- */
- public function getGroupName()
- {
- return $this->getViewState('GroupName','');
- }
-
- /**
- * Sets the name of the group that the radio button belongs to.
- * The group is unique among the control's naming container.
- * @param string the group name
- * @see setUniqueGroupName
- */
- public function setGroupName($value)
- {
- $this->setViewState('GroupName',$value,'');
- $this->_uniqueGroupName=null;
- }
-
- /**
- * Add the group name as post data loader if group name is set.
- */
- protected function addToPostDataLoader()
- {
- parent::addToPostDataLoader();
- $group = $this->getGroupName();
- if(!empty($group) || $this->getViewState('UniqueGroupName','') !== '')
- $this->getPage()->registerPostDataLoader($this->getUniqueGroupName());
- }
- /**
- * @return string the name used to fetch radiobutton post data
- */
- public function getUniqueGroupName()
- {
- if(($groupName=$this->getViewState('UniqueGroupName',''))!=='')
- return $groupName;
- else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null)
- {
- $groupName=$this->getGroupName();
- $this->_previousUniqueID=$uniqueID;
- if($uniqueID!=='')
- {
- if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false)
- {
- if($groupName!=='')
- $groupName=substr($uniqueID,0,$pos+1).$groupName;
- else if($this->getNamingContainer() instanceof TRadioButtonList)
- $groupName=substr($uniqueID,0,$pos);
- }
- if($groupName==='')
- $groupName=$uniqueID;
- }
- $this->_uniqueGroupName=$groupName;
- }
- return $this->_uniqueGroupName;
- }
-
- /**
- * Sets the unique group name that the radio button belongs to.
- * A unique group is a radiobutton group unique among the whole page hierarchy,
- * while the {@link setGroupName GroupName} specifies a group that is unique
- * among the control's naming container only.
- * For example, each cell of a {@link TDataGrid} is a naming container.
- * If you specify {@link setGroupName GroupName} for a radiobutton in a cell,
- * it groups together radiobutton within a cell, but not the other, even though
- * they have the same {@link setGroupName GroupName}.
- * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead,
- * it will group all appropriate radio buttons on the whole page hierarchy.
- * Note, when both {@link setUniqueGroupName UniqueGroupName} and
- * {@link setGroupName GroupName}, the former takes precedence.
- * @param string the group name
- * @see setGroupName
- */
- public function setUniqueGroupName($value)
- {
- $this->setViewState('UniqueGroupName',$value,'');
- }
-
- /**
- * Gets an array of radiobuttons whose group name is the same as this radiobutton's.
- * Note, only those radiobuttons that are on the current page hierarchy may be
- * returned in the result.
- * @return array list of TRadioButton with the same group
- */
- public function getRadioButtonsInGroup()
- {
- $group = $this->getUniqueGroupName();
- $buttons = array();
- foreach(self::$_activeButtons as $control)
- {
- if($control->getUniqueGroupName() === $group)
- $buttons[] = $control;
- }
- return $buttons;
- }
-
- /**
- * @return string the value attribute to be rendered
- */
- protected function getValueAttribute()
- {
- if(($value=parent::getValueAttribute())==='')
- return $this->getUniqueID();
- else
- return $value;
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Renders a radiobutton input element.
- * @param THtmlWriter the writer for the rendering purpose
- * @param string checkbox id
- * @param string onclick js
- */
- protected function renderInputTag($writer,$clientID,$onclick)
- {
- if($clientID!=='')
- $writer->addAttribute('id',$clientID);
- $writer->addAttribute('type','radio');
- $writer->addAttribute('name',$this->getUniqueGroupName());
- $writer->addAttribute('value',$this->getValueAttribute());
- if(!empty($onclick))
- $writer->addAttribute('onclick',$onclick);
- if($this->getChecked())
- $writer->addAttribute('checked','checked');
- if(!$this->getEnabled(true))
- $writer->addAttribute('disabled','disabled');
-
- $page=$this->getPage();
- if($this->getEnabled(true)
- && $this->getEnableClientScript()
- && $this->getAutoPostBack()
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
-
- if(($accesskey=$this->getAccessKey())!=='')
- $writer->addAttribute('accesskey',$accesskey);
- if(($tabindex=$this->getTabIndex())>0)
- $writer->addAttribute('tabindex',"$tabindex");
- if($attributes=$this->getViewState('InputAttributes',null))
- $writer->addAttributes($attributes);
- $writer->renderBeginTag('input');
- $writer->renderEndTag();
- }
-
- /**
- * Renders the client-script code.
- */
- protected function renderClientControlScript($writer)
- {
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRadioButton';
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TCheckBox parent class
+ */
+Prado::using('System.Web.UI.WebControls.TCheckBox');
+/**
+ * Using TRadioButtonList class
+ */
+Prado::using('System.Web.UI.WebControls.TRadioButtonList');
+
+/**
+ * TRadioButton class
+ *
+ * TRadioButton displays a radio button on the page.
+ * You can specify the caption to display beside the radio buttonby setting
+ * the {@link setText Text} property. The caption can appear either on the right
+ * or left of the radio button, which is determined by the {@link setTextAlign TextAlign}
+ * property.
+ *
+ * To determine whether the TRadioButton component is checked, test the {@link getChecked Checked}
+ * property. The {@link onCheckedChanged OnCheckedChanged} event is raised when
+ * the {@link getChecked Checked} state of the TRadioButton component changes
+ * between posts to the server. You can provide an event handler for
+ * the {@link onCheckedChanged OnCheckedChanged} event to to programmatically
+ * control the actions performed when the state of the TRadioButton component changes
+ * between posts to the server.
+ *
+ * TRadioButton uses {@link setGroupName GroupName} to group together a set of radio buttons.
+ * Once the {@link setGroupName GroupName} is set, you can use the {@link getRadioButtonsInGroup}
+ * method to get an array of TRadioButtons having the same group name.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, changing the radio button state
+ * will cause postback action. And if {@link setCausesValidation CausesValidation}
+ * is true, validation will also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * Note, {@link setText Text} is rendered as is. Make sure it does not contain unwanted characters
+ * that may bring security vulnerabilities.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRadioButton extends TCheckBox
+{
+ /**
+ * @param array list of radio buttons that are on the current page hierarchy
+ */
+ private static $_activeButtons=array();
+ /**
+ * @var integer number of radio buttons created
+ */
+ private static $_buttonCount=0;
+ /**
+ * @var integer global ID of this radiobutton
+ */
+ private $_globalID;
+ /**
+ * @var string previous UniqueID (used to calculate UniqueGroup)
+ */
+ private $_previousUniqueID=null;
+ /**
+ * @var string the name used to fetch radiobutton post data
+ */
+ private $_uniqueGroupName=null;
+
+ /**
+ * Constructor.
+ * Registers the radiobutton in a global radiobutton collection.
+ * If overridden, the parent implementation must be invoked first.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->_globalID = self::$_buttonCount++;
+ }
+
+ /**
+ * Registers the radio button groupings. If overriding onInit method,
+ * ensure to call parent implemenation.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ self::$_activeButtons[$this->_globalID]=$this;
+ }
+
+ /**
+ * Unregisters the radio button groupings. If overriding onInit method,
+ * ensure to call parent implemenation.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onUnLoad($param)
+ {
+ unset(self::$_activeButtons[$this->_globalID]);
+ parent::onUnLoad($param);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the control has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $uniqueGroupName=$this->getUniqueGroupName();
+ $value=isset($values[$uniqueGroupName])?$values[$uniqueGroupName]:null;
+ if($value!==null && $value===$this->getValueAttribute())
+ {
+ if(!$this->getChecked())
+ {
+ $this->setChecked(true);
+ return true;
+ }
+ else
+ return false;
+ }
+ else if($this->getChecked())
+ $this->setChecked(false);
+ return false;
+ }
+
+ /**
+ * @return string the name of the group that the radio button belongs to. Defaults to empty.
+ */
+ public function getGroupName()
+ {
+ return $this->getViewState('GroupName','');
+ }
+
+ /**
+ * Sets the name of the group that the radio button belongs to.
+ * The group is unique among the control's naming container.
+ * @param string the group name
+ * @see setUniqueGroupName
+ */
+ public function setGroupName($value)
+ {
+ $this->setViewState('GroupName',$value,'');
+ $this->_uniqueGroupName=null;
+ }
+
+ /**
+ * Add the group name as post data loader if group name is set.
+ */
+ protected function addToPostDataLoader()
+ {
+ parent::addToPostDataLoader();
+ $group = $this->getGroupName();
+ if(!empty($group) || $this->getViewState('UniqueGroupName','') !== '')
+ $this->getPage()->registerPostDataLoader($this->getUniqueGroupName());
+ }
+ /**
+ * @return string the name used to fetch radiobutton post data
+ */
+ public function getUniqueGroupName()
+ {
+ if(($groupName=$this->getViewState('UniqueGroupName',''))!=='')
+ return $groupName;
+ else if(($uniqueID=$this->getUniqueID())!==$this->_previousUniqueID || $this->_uniqueGroupName===null)
+ {
+ $groupName=$this->getGroupName();
+ $this->_previousUniqueID=$uniqueID;
+ if($uniqueID!=='')
+ {
+ if(($pos=strrpos($uniqueID,TControl::ID_SEPARATOR))!==false)
+ {
+ if($groupName!=='')
+ $groupName=substr($uniqueID,0,$pos+1).$groupName;
+ else if($this->getNamingContainer() instanceof TRadioButtonList)
+ $groupName=substr($uniqueID,0,$pos);
+ }
+ if($groupName==='')
+ $groupName=$uniqueID;
+ }
+ $this->_uniqueGroupName=$groupName;
+ }
+ return $this->_uniqueGroupName;
+ }
+
+ /**
+ * Sets the unique group name that the radio button belongs to.
+ * A unique group is a radiobutton group unique among the whole page hierarchy,
+ * while the {@link setGroupName GroupName} specifies a group that is unique
+ * among the control's naming container only.
+ * For example, each cell of a {@link TDataGrid} is a naming container.
+ * If you specify {@link setGroupName GroupName} for a radiobutton in a cell,
+ * it groups together radiobutton within a cell, but not the other, even though
+ * they have the same {@link setGroupName GroupName}.
+ * On the contratry, if {@link setUniqueGroupName UniqueGroupName} is used instead,
+ * it will group all appropriate radio buttons on the whole page hierarchy.
+ * Note, when both {@link setUniqueGroupName UniqueGroupName} and
+ * {@link setGroupName GroupName}, the former takes precedence.
+ * @param string the group name
+ * @see setGroupName
+ */
+ public function setUniqueGroupName($value)
+ {
+ $this->setViewState('UniqueGroupName',$value,'');
+ }
+
+ /**
+ * Gets an array of radiobuttons whose group name is the same as this radiobutton's.
+ * Note, only those radiobuttons that are on the current page hierarchy may be
+ * returned in the result.
+ * @return array list of TRadioButton with the same group
+ */
+ public function getRadioButtonsInGroup()
+ {
+ $group = $this->getUniqueGroupName();
+ $buttons = array();
+ foreach(self::$_activeButtons as $control)
+ {
+ if($control->getUniqueGroupName() === $group)
+ $buttons[] = $control;
+ }
+ return $buttons;
+ }
+
+ /**
+ * @return string the value attribute to be rendered
+ */
+ protected function getValueAttribute()
+ {
+ if(($value=parent::getValueAttribute())==='')
+ return $this->getUniqueID();
+ else
+ return $value;
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Renders a radiobutton input element.
+ * @param THtmlWriter the writer for the rendering purpose
+ * @param string checkbox id
+ * @param string onclick js
+ */
+ protected function renderInputTag($writer,$clientID,$onclick)
+ {
+ if($clientID!=='')
+ $writer->addAttribute('id',$clientID);
+ $writer->addAttribute('type','radio');
+ $writer->addAttribute('name',$this->getUniqueGroupName());
+ $writer->addAttribute('value',$this->getValueAttribute());
+ if(!empty($onclick))
+ $writer->addAttribute('onclick',$onclick);
+ if($this->getChecked())
+ $writer->addAttribute('checked','checked');
+ if(!$this->getEnabled(true))
+ $writer->addAttribute('disabled','disabled');
+
+ $page=$this->getPage();
+ if($this->getEnabled(true)
+ && $this->getEnableClientScript()
+ && $this->getAutoPostBack()
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+
+ if(($accesskey=$this->getAccessKey())!=='')
+ $writer->addAttribute('accesskey',$accesskey);
+ if(($tabindex=$this->getTabIndex())>0)
+ $writer->addAttribute('tabindex',"$tabindex");
+ if($attributes=$this->getViewState('InputAttributes',null))
+ $writer->addAttributes($attributes);
+ $writer->renderBeginTag('input');
+ $writer->renderEndTag();
+ }
+
+ /**
+ * Renders the client-script code.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRadioButton';
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TRangeValidator.php b/framework/Web/UI/WebControls/TRangeValidator.php
index d8d2d20d..57538e88 100644
--- a/framework/Web/UI/WebControls/TRangeValidator.php
+++ b/framework/Web/UI/WebControls/TRangeValidator.php
@@ -1,360 +1,360 @@
-<?php
-/**
- * TRangeValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TRangeValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRangeValidator class
- *
- * TRangeValidator tests whether an input value is within a specified range.
- *
- * TRangeValidator uses three key properties to perform its validation.
- * The {@link setMinValue MinValue} and {@link setMaxValue MaxValue}
- * properties specify the minimum and maximum values of the valid range.
- * The {@link setDataType DataType} property is used to specify the
- * data type of the value and the minimum and maximum range values.
- * These values are converted to this data type before the validation
- * operation is performed. The following value types are supported:
- * - <b>Integer</b> A 32-bit signed integer data type.
- * - <b>Float</b> A double-precision floating point number data type.
- * - <b>Date</b> A date data type. The date format can be specified by
- * setting {@link setDateFormat DateFormat} property, which must be recognizable
- * by {@link TSimpleDateFormatter}. If the property is not set,
- * the GNU date syntax is assumed.
- * - <b>String</b> A string data type.
- * - <b>StringLength</b> check for string length.
- *
- * If {@link setStrictComparison StrictComparison} is true, then the ranges
- * are compared as strictly less than the max value and/or strictly greater than the min value.
- *
- * The TRangeValidator allows a special DataType "StringLength" that
- * can be used to verify minimum and maximum string length. The
- * {@link setCharset Charset} property can be used to force a particular
- * charset for comparison. Otherwise, the application charset is used and is
- * defaulted as UTF-8.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRangeValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRangeValidator';
- }
-
- /**
- * @return string the minimum value of the validation range.
- */
- public function getMinValue()
- {
- return $this->getViewState('MinValue','');
- }
-
- /**
- * Sets the minimum value of the validation range.
- * @param string the minimum value
- */
- public function setMinValue($value)
- {
- $this->setViewState('MinValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the maximum value of the validation range.
- */
- public function getMaxValue()
- {
- return $this->getViewState('MaxValue','');
- }
-
- /**
- * Sets the maximum value of the validation range.
- * @param string the maximum value
- */
- public function setMaxValue($value)
- {
- $this->setViewState('MaxValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @param boolean true to perform strict comparison (i.e. strictly less than max and/or strictly greater than min).
- */
- public function setStrictComparison($value)
- {
- $this->setViewState('StrictComparison', TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean true to perform strict comparison.
- */
- public function getStrictComparison()
- {
- return $this->getViewState('StrictComparison', false);
- }
-
- /**
- * @return TRangeValidationDataType the data type that the values being compared are
- * converted to before the comparison is made. Defaults to TRangeValidationDataType::String.
- */
- public function getDataType()
- {
- return $this->getViewState('DataType',TRangeValidationDataType::String);
- }
-
- /**
- * Sets the data type that the values being compared are converted to before the comparison is made.
- * @param TRangeValidationDataType the data type
- */
- public function setDataType($value)
- {
- $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TRangeValidationDataType'),TRangeValidationDataType::String);
- }
-
- /**
- * Sets the date format for a date validation
- * @param string the date format value
- */
- public function setDateFormat($value)
- {
- $this->setViewState('DateFormat', $value, '');
- }
-
- /**
- * @return string the date validation date format if any
- */
- public function getDateFormat()
- {
- return $this->getViewState('DateFormat', '');
- }
-
- /**
- * @param string charset for string length comparison.
- */
- public function setCharset($value)
- {
- $this->setViewState('Charset', $value, '');
- }
-
- /**
- * @return string charset for string length comparison.
- */
- public function getCharset()
- {
- return $this->getViewState('Charset', '');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data is within the range.
- * The validation always succeeds if the input data is empty.
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $value=$this->getValidationValue($this->getValidationTarget());
- if($value==='')
- return true;
-
- switch($this->getDataType())
- {
- case TRangeValidationDataType::Integer:
- return $this->isValidInteger($value);
- case TRangeValidationDataType::Float:
- return $this->isValidFloat($value);
- case TRangeValidationDataType::Date:
- return $this->isValidDate($value);
- case TRangeValidationDataType::StringLength:
- return $this->isValidStringLength($value);
- default:
- return $this->isValidString($value);
- }
- }
-
- /**
- * Determine if the value is within the integer range.
- * @param string value to validate true
- * @return boolean true if within integer range.
- */
- protected function isValidInteger($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRangeValidator class
+ *
+ * TRangeValidator tests whether an input value is within a specified range.
+ *
+ * TRangeValidator uses three key properties to perform its validation.
+ * The {@link setMinValue MinValue} and {@link setMaxValue MaxValue}
+ * properties specify the minimum and maximum values of the valid range.
+ * The {@link setDataType DataType} property is used to specify the
+ * data type of the value and the minimum and maximum range values.
+ * These values are converted to this data type before the validation
+ * operation is performed. The following value types are supported:
+ * - <b>Integer</b> A 32-bit signed integer data type.
+ * - <b>Float</b> A double-precision floating point number data type.
+ * - <b>Date</b> A date data type. The date format can be specified by
+ * setting {@link setDateFormat DateFormat} property, which must be recognizable
+ * by {@link TSimpleDateFormatter}. If the property is not set,
+ * the GNU date syntax is assumed.
+ * - <b>String</b> A string data type.
+ * - <b>StringLength</b> check for string length.
+ *
+ * If {@link setStrictComparison StrictComparison} is true, then the ranges
+ * are compared as strictly less than the max value and/or strictly greater than the min value.
+ *
+ * The TRangeValidator allows a special DataType "StringLength" that
+ * can be used to verify minimum and maximum string length. The
+ * {@link setCharset Charset} property can be used to force a particular
+ * charset for comparison. Otherwise, the application charset is used and is
+ * defaulted as UTF-8.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRangeValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRangeValidator';
+ }
+
+ /**
+ * @return string the minimum value of the validation range.
+ */
+ public function getMinValue()
+ {
+ return $this->getViewState('MinValue','');
+ }
+
+ /**
+ * Sets the minimum value of the validation range.
+ * @param string the minimum value
+ */
+ public function setMinValue($value)
+ {
+ $this->setViewState('MinValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the maximum value of the validation range.
+ */
+ public function getMaxValue()
+ {
+ return $this->getViewState('MaxValue','');
+ }
+
+ /**
+ * Sets the maximum value of the validation range.
+ * @param string the maximum value
+ */
+ public function setMaxValue($value)
+ {
+ $this->setViewState('MaxValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @param boolean true to perform strict comparison (i.e. strictly less than max and/or strictly greater than min).
+ */
+ public function setStrictComparison($value)
+ {
+ $this->setViewState('StrictComparison', TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean true to perform strict comparison.
+ */
+ public function getStrictComparison()
+ {
+ return $this->getViewState('StrictComparison', false);
+ }
+
+ /**
+ * @return TRangeValidationDataType the data type that the values being compared are
+ * converted to before the comparison is made. Defaults to TRangeValidationDataType::String.
+ */
+ public function getDataType()
+ {
+ return $this->getViewState('DataType',TRangeValidationDataType::String);
+ }
+
+ /**
+ * Sets the data type that the values being compared are converted to before the comparison is made.
+ * @param TRangeValidationDataType the data type
+ */
+ public function setDataType($value)
+ {
+ $this->setViewState('DataType',TPropertyValue::ensureEnum($value,'TRangeValidationDataType'),TRangeValidationDataType::String);
+ }
+
+ /**
+ * Sets the date format for a date validation
+ * @param string the date format value
+ */
+ public function setDateFormat($value)
+ {
+ $this->setViewState('DateFormat', $value, '');
+ }
+
+ /**
+ * @return string the date validation date format if any
+ */
+ public function getDateFormat()
+ {
+ return $this->getViewState('DateFormat', '');
+ }
+
+ /**
+ * @param string charset for string length comparison.
+ */
+ public function setCharset($value)
+ {
+ $this->setViewState('Charset', $value, '');
+ }
+
+ /**
+ * @return string charset for string length comparison.
+ */
+ public function getCharset()
+ {
+ return $this->getViewState('Charset', '');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data is within the range.
+ * The validation always succeeds if the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $value=$this->getValidationValue($this->getValidationTarget());
+ if($value==='')
+ return true;
+
+ switch($this->getDataType())
+ {
+ case TRangeValidationDataType::Integer:
+ return $this->isValidInteger($value);
+ case TRangeValidationDataType::Float:
+ return $this->isValidFloat($value);
+ case TRangeValidationDataType::Date:
+ return $this->isValidDate($value);
+ case TRangeValidationDataType::StringLength:
+ return $this->isValidStringLength($value);
+ default:
+ return $this->isValidString($value);
+ }
+ }
+
+ /**
+ * Determine if the value is within the integer range.
+ * @param string value to validate true
+ * @return boolean true if within integer range.
+ */
+ protected function isValidInteger($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
$valid=preg_match('/^[-+]?[0-9]+$/',trim($value));
- $value=intval($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value, intval($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,intval($maxValue));
- return $valid;
- }
-
- protected function isLessThan($left,$right)
- {
- return $this->getStrictComparison() ? $left < $right : $left <= $right;
- }
-
- protected function isGreaterThan($left, $right)
- {
- return $this->getStrictComparison() ? $left > $right : $left >= $right;
- }
-
- /**
- * Determine if the value is within the specified float range.
- * @param string value to validate
- * @return boolean true if within range.
- */
- protected function isValidFloat($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
- $value=floatval($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,floatval($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,floatval($maxValue));
- return $valid;
- }
-
- /**
- * Determine if the date is within the specified range.
- * Uses pradoParseDate and strtotime to get the date from string.
- * @param string date as string to validate
- * @return boolean true if within range.
- */
- protected function isValidDate($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
-
- $dateFormat = $this->getDateFormat();
- if($dateFormat!=='')
- {
- $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
- $value = $formatter->parse($value, $dateFormat);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,$formatter->parse($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,$formatter->parse($maxValue));
- return $valid;
- }
- else
- {
- $value=strtotime($value);
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan($value,strtotime($minValue));
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan($value,strtotime($maxValue));
- return $valid;
- }
- }
-
- /**
- * Compare the string with a minimum and a maxiumum value.
- * Uses strcmp for comparision.
- * @param string value to compare with.
- * @return boolean true if the string is within range.
- */
- protected function isValidString($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
- if($minValue!=='')
- $valid=$valid && $this->isGreaterThan(strcmp($value,$minValue),0);
- if($maxValue!=='')
- $valid=$valid && $this->isLessThan(strcmp($value,$maxValue),0);
- return $valid;
- }
-
- /**
- * @param string string for comparision
- * @return boolean true if min and max string length are satisfied.
- */
- protected function isValidStringLength($value)
- {
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
-
- $valid=true;
- $charset = $this->getCharset();
- if($charset==='')
- {
- $app= $this->getApplication()->getGlobalization();
- $charset = $app ? $app->getCharset() : null;
- if(!$charset)
- $charset = 'UTF-8';
- }
-
- $length = iconv_strlen($value, $charset);
- if($minValue!=='')
- $valid = $valid && $this->isGreaterThan($length,intval($minValue));
- if($maxValue!=='')
- $valid = $valid && $this->isLessThan($length,intval($maxValue));
- return $valid;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options=parent::getClientScriptOptions();
- $options['MinValue']=$this->getMinValue();
- $options['MaxValue']=$this->getMaxValue();
- $options['DataType']=$this->getDataType();
- $options['StrictComparison']=$this->getStrictComparison();
- if(($dateFormat=$this->getDateFormat())!=='')
- $options['DateFormat']=$dateFormat;
- return $options;
- }
-}
-
-
-/**
- * TRangeValidationDataType class.
- * TRangeValidationDataType defines the enumerable type for the possible data types that
- * a range validator can validate upon.
- *
- * The following enumerable values are defined:
- * - Integer
- * - Float
- * - Date
- * - String
- * - StringLength
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRangeValidationDataType extends TValidationDataType
-{
- const StringLength='StringLength';
-}
+ $value=intval($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value, intval($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,intval($maxValue));
+ return $valid;
+ }
+
+ protected function isLessThan($left,$right)
+ {
+ return $this->getStrictComparison() ? $left < $right : $left <= $right;
+ }
+
+ protected function isGreaterThan($left, $right)
+ {
+ return $this->getStrictComparison() ? $left > $right : $left >= $right;
+ }
+
+ /**
+ * Determine if the value is within the specified float range.
+ * @param string value to validate
+ * @return boolean true if within range.
+ */
+ protected function isValidFloat($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
+ $value=floatval($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,floatval($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,floatval($maxValue));
+ return $valid;
+ }
+
+ /**
+ * Determine if the date is within the specified range.
+ * Uses pradoParseDate and strtotime to get the date from string.
+ * @param string date as string to validate
+ * @return boolean true if within range.
+ */
+ protected function isValidDate($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+
+ $dateFormat = $this->getDateFormat();
+ if($dateFormat!=='')
+ {
+ $formatter=Prado::createComponent('System.Util.TSimpleDateFormatter', $dateFormat);
+ $value = $formatter->parse($value, $dateFormat);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,$formatter->parse($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,$formatter->parse($maxValue));
+ return $valid;
+ }
+ else
+ {
+ $value=strtotime($value);
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan($value,strtotime($minValue));
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan($value,strtotime($maxValue));
+ return $valid;
+ }
+ }
+
+ /**
+ * Compare the string with a minimum and a maxiumum value.
+ * Uses strcmp for comparision.
+ * @param string value to compare with.
+ * @return boolean true if the string is within range.
+ */
+ protected function isValidString($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+ if($minValue!=='')
+ $valid=$valid && $this->isGreaterThan(strcmp($value,$minValue),0);
+ if($maxValue!=='')
+ $valid=$valid && $this->isLessThan(strcmp($value,$maxValue),0);
+ return $valid;
+ }
+
+ /**
+ * @param string string for comparision
+ * @return boolean true if min and max string length are satisfied.
+ */
+ protected function isValidStringLength($value)
+ {
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+
+ $valid=true;
+ $charset = $this->getCharset();
+ if($charset==='')
+ {
+ $app= $this->getApplication()->getGlobalization();
+ $charset = $app ? $app->getCharset() : null;
+ if(!$charset)
+ $charset = 'UTF-8';
+ }
+
+ $length = iconv_strlen($value, $charset);
+ if($minValue!=='')
+ $valid = $valid && $this->isGreaterThan($length,intval($minValue));
+ if($maxValue!=='')
+ $valid = $valid && $this->isLessThan($length,intval($maxValue));
+ return $valid;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options=parent::getClientScriptOptions();
+ $options['MinValue']=$this->getMinValue();
+ $options['MaxValue']=$this->getMaxValue();
+ $options['DataType']=$this->getDataType();
+ $options['StrictComparison']=$this->getStrictComparison();
+ if(($dateFormat=$this->getDateFormat())!=='')
+ $options['DateFormat']=$dateFormat;
+ return $options;
+ }
+}
+
+
+/**
+ * TRangeValidationDataType class.
+ * TRangeValidationDataType defines the enumerable type for the possible data types that
+ * a range validator can validate upon.
+ *
+ * The following enumerable values are defined:
+ * - Integer
+ * - Float
+ * - Date
+ * - String
+ * - StringLength
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRangeValidationDataType extends TValidationDataType
+{
+ const StringLength='StringLength';
+}
diff --git a/framework/Web/UI/WebControls/TRatingList.php b/framework/Web/UI/WebControls/TRatingList.php
index dfb11371..cc813755 100644
--- a/framework/Web/UI/WebControls/TRatingList.php
+++ b/framework/Web/UI/WebControls/TRatingList.php
@@ -1,359 +1,359 @@
-<?php
-/**
- * TRatingList class file.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TRadioButtonList class
- */
-Prado::using('System.Web.UI.WebControls.TRadioButtonList');
-
-/**
- * TRatingList class.
- *
- * This class is EXPERIMENTAL.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRatingList extends TRadioButtonList
-{
- /**
- * Script path relative to the TClientScriptManager::SCRIPT_PATH
- */
- const SCRIPT_PATH='prado/ratings';
-
- /**
- * @var array list of published rating images.
- */
- private $_ratingImages = array();
-
- /**
- * Sets the default repeat direction to horizontal.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setRepeatDirection(TRepeatDirection::Horizontal);
- }
-
- /**
- * @return boolean whether the items in the column can be edited. Defaults to false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the items in the column can be edited
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @return boolean whether the rating list can be edited. Defaults to true.
- */
- public function getAllowInput()
- {
- return !$this->getReadOnly();
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @param boolean whether the rating list can be edited
- */
- public function setAllowInput($value)
- {
- $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * Wrapper for {@link setReadOnly ReadOnly} property.
- * @param boolean whether the rating list can be edited
- */
- public function setEnabled($value)
- {
- $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
- }
-
- /**
- * The repeat layout must be Table.
- * @param string repeat layout type
- * @throws TInvaliddataValueException when repeat layout is not Table.
- */
- public function setRepeatLayout($value)
- {
- if($value!==TRepeatLayout::Table)
- throw new TInvalidDataValueException('ratinglist_table_layout_only');
- else
- parent::setRepeatLayout($value);
- }
-
- /**
- * @return float rating value.
- */
- public function getRating()
- {
- $rating = $this->getViewState('Rating', null);
- if ($rating === null)
- return $this->getSelectedIndex()+1;
- else
- return $rating;
- }
-
- /**
- * @param float rating value, also sets the selected Index
- */
- public function setRating($value)
- {
- $value = TPropertyValue::ensureFloat($value);
- $this->setViewState('Rating', $value, null);
- $index = $this->getRatingIndex($value);
- parent::setSelectedIndex($index);
- }
-
- public function setSelectedIndex($value)
- {
- $this->setRating($value+1);
- parent::setSelectedIndex($value);
- }
-
- /**
- * @param float rating value
- * @return int rating as integer
- */
- protected function getRatingIndex($rating)
- {
- $interval = $this->getHalfRatingInterval();
- $base = intval($rating)-1;
- $remainder = $rating-$base-1;
- return $remainder > $interval[1] ? $base+1 : $base;
- }
-
- /**
- * @param int change the rating selection index
- */
- public function onSelectedIndexChanged($param)
- {
- $value = $this->getRating();
- $value = TPropertyValue::ensureInteger($value);
- $this->setRating($value);
- parent::onSelectedIndexChanged($param);
- }
-
- /**
- * @return string control or html element ID for displaying a caption.
- */
- public function getCaptionID()
- {
- return $this->getViewState('CaptionID', '');
- }
-
- /**
- * @param string control or html element ID for displaying a caption.
- */
- public function setCaptionID($value)
- {
- $this->setViewState('CaptionID', $value, '');
- }
-
- protected function getCaptionControl()
- {
- if(($id=$this->getCaptionID())!=='')
- {
- if($control=$this->getParent()->findControl($id))
- return $control;
- }
- throw new TInvalidDataValueException(
- 'ratinglist_invalid_caption_id',$id,$this->getID());
- }
-
- /**
- * @return string caption text. Default is "Rate It:".
- */
- public function getCaption()
- {
- return $this->getCaptionControl()->getText();
- }
-
- /**
- * @return TRatingListStyle current rating style
- */
- public function setCaption($value)
- {
- $this->getCaptionControl()->setText($value);
- }
-
- /**
- * @param string set the rating style, default is "default"
- */
- public function setRatingStyle($value)
- {
- $this->setViewState('RatingStyle', $value, 'default');
- }
-
- /**
- * @return TRatingListStyle current rating style
- */
- public function getRatingStyle()
- {
- return $this->getViewState('RatingStyle', 'default');
- }
-
- /**
- * @return string rating style css class name.
- */
- protected function getRatingStyleCssClass()
- {
- return 'TRatingList_'.$this->getRatingStyle();
- }
-
- /**
- * Sets the interval such that those rating values within the interval
- * will be considered as a half star rating.
- * @param array rating display half value interval, default is array(0.3, 0.7);
- */
- public function setHalfRatingInterval($value)
- {
- $this->setViewState('HalfRating',
- TPropertyValue::ensureArray($value), array(0.3, 0.7));
- }
-
- /**
- * @return array rating display half value interval, default is array(0.3, 0.7);
- */
- public function getHalfRatingInterval()
- {
- return $this->getViewState('HalfRating', array(0.3, 0.7));
- }
-
- /**
- * @return array list of post back options.
- */
- protected function getPostBackOptions()
- {
- $options = parent::getPostBackOptions();
- $options['AutoPostBack'] = $this->getAutoPostBack();
- $options['ReadOnly'] = $this->getReadOnly();
- $options['Style'] = $this->getRatingStyleCssClass();
- $options['CaptionID'] = $this->getCaptionControlID();
- $options['SelectedIndex'] = $this->getSelectedIndex();
- $options['Rating'] = $this->getRating();
- $options['HalfRating'] = $this->getHalfRatingInterval();
- return $options;
- }
-
- /**
- * @return string find the client ID of the caption control.
- */
- protected function getCaptionControlID()
- {
- if(($id=$this->getCaptionID())!=='')
- {
- if($control=$this->getParent()->findControl($id))
- {
- if($control->getVisible(true))
- return $control->getClientID();
- }
- else
- return $id;
- }
- return '';
- }
-
- /**
- * Publish the the rating style css file and rating image files.
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
- $this->publishStyle($this->getRatingStyle());
- $this->_ratingImages = $this->publishImages($this->getRatingStyle());
- $this->registerClientScript();
- }
-
- /**
- * @param string rating style name
- * @return string URL of the css style file
- */
- protected function publishStyle($style)
- {
- $cs = $this->getPage()->getClientScript();
- $url = $this->getAssetUrl($style.'.css');
- if(!$cs->isStyleSheetFileRegistered($url))
- $cs->registerStyleSheetFile($url, $url);
- return $url;
- }
-
- /**
- * @param string rating style name
- * @param string rating image file extension, default is '.gif'
- * @return array URL of publish the rating images
- */
- protected function publishImages($style, $fileExt='.gif')
- {
- $types = array('blank', 'selected', 'half', 'combined');
- $files = array();
- foreach($types as $type)
- $files[$type] = $this->getAssetUrl("{$style}_{$type}{$fileExt}");
- return $files;
- }
-
- /**
- * Registers the relevant JavaScript.
- */
- protected function registerClientScript()
- {
- $cs=$this->getPage()->getClientScript();
- $cs->registerPradoScript('ratings');
- }
-
- /**
- * @param string asset file in the self::SCRIPT_PATH directory.
- * @return string asset file url.
- */
- protected function getAssetUrl($file='')
- {
- $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
- return $base.'/'.self::SCRIPT_PATH.'/'.$file;
- }
-
- /**
- * Add rating style class name to the class attribute
- * when {@link setReadOnly ReadOnly} property is true and when the
- * {@link setCssClass CssClass} property is empty.
- * @param THtmlWriter renderer
- */
- public function render($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $this->getPage()->getClientScript()->registerPostBackControl(
- $this->getClientClassName(), $this->getPostBackOptions());
- parent::render($writer);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRatingList';
- }
-}
-
+<?php
+/**
+ * TRatingList class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TRadioButtonList class
+ */
+Prado::using('System.Web.UI.WebControls.TRadioButtonList');
+
+/**
+ * TRatingList class.
+ *
+ * This class is EXPERIMENTAL.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Bradley Booms <bradley[dot]booms[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRatingList extends TRadioButtonList
+{
+ /**
+ * Script path relative to the TClientScriptManager::SCRIPT_PATH
+ */
+ const SCRIPT_PATH='prado/ratings';
+
+ /**
+ * @var array list of published rating images.
+ */
+ private $_ratingImages = array();
+
+ /**
+ * Sets the default repeat direction to horizontal.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setRepeatDirection(TRepeatDirection::Horizontal);
+ }
+
+ /**
+ * @return boolean whether the items in the column can be edited. Defaults to false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the items in the column can be edited
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @return boolean whether the rating list can be edited. Defaults to true.
+ */
+ public function getAllowInput()
+ {
+ return !$this->getReadOnly();
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @param boolean whether the rating list can be edited
+ */
+ public function setAllowInput($value)
+ {
+ $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * Wrapper for {@link setReadOnly ReadOnly} property.
+ * @param boolean whether the rating list can be edited
+ */
+ public function setEnabled($value)
+ {
+ $this->setReadOnly(!TPropertyValue::ensureBoolean($value));
+ }
+
+ /**
+ * The repeat layout must be Table.
+ * @param string repeat layout type
+ * @throws TInvaliddataValueException when repeat layout is not Table.
+ */
+ public function setRepeatLayout($value)
+ {
+ if($value!==TRepeatLayout::Table)
+ throw new TInvalidDataValueException('ratinglist_table_layout_only');
+ else
+ parent::setRepeatLayout($value);
+ }
+
+ /**
+ * @return float rating value.
+ */
+ public function getRating()
+ {
+ $rating = $this->getViewState('Rating', null);
+ if ($rating === null)
+ return $this->getSelectedIndex()+1;
+ else
+ return $rating;
+ }
+
+ /**
+ * @param float rating value, also sets the selected Index
+ */
+ public function setRating($value)
+ {
+ $value = TPropertyValue::ensureFloat($value);
+ $this->setViewState('Rating', $value, null);
+ $index = $this->getRatingIndex($value);
+ parent::setSelectedIndex($index);
+ }
+
+ public function setSelectedIndex($value)
+ {
+ $this->setRating($value+1);
+ parent::setSelectedIndex($value);
+ }
+
+ /**
+ * @param float rating value
+ * @return int rating as integer
+ */
+ protected function getRatingIndex($rating)
+ {
+ $interval = $this->getHalfRatingInterval();
+ $base = intval($rating)-1;
+ $remainder = $rating-$base-1;
+ return $remainder > $interval[1] ? $base+1 : $base;
+ }
+
+ /**
+ * @param int change the rating selection index
+ */
+ public function onSelectedIndexChanged($param)
+ {
+ $value = $this->getRating();
+ $value = TPropertyValue::ensureInteger($value);
+ $this->setRating($value);
+ parent::onSelectedIndexChanged($param);
+ }
+
+ /**
+ * @return string control or html element ID for displaying a caption.
+ */
+ public function getCaptionID()
+ {
+ return $this->getViewState('CaptionID', '');
+ }
+
+ /**
+ * @param string control or html element ID for displaying a caption.
+ */
+ public function setCaptionID($value)
+ {
+ $this->setViewState('CaptionID', $value, '');
+ }
+
+ protected function getCaptionControl()
+ {
+ if(($id=$this->getCaptionID())!=='')
+ {
+ if($control=$this->getParent()->findControl($id))
+ return $control;
+ }
+ throw new TInvalidDataValueException(
+ 'ratinglist_invalid_caption_id',$id,$this->getID());
+ }
+
+ /**
+ * @return string caption text. Default is "Rate It:".
+ */
+ public function getCaption()
+ {
+ return $this->getCaptionControl()->getText();
+ }
+
+ /**
+ * @return TRatingListStyle current rating style
+ */
+ public function setCaption($value)
+ {
+ $this->getCaptionControl()->setText($value);
+ }
+
+ /**
+ * @param string set the rating style, default is "default"
+ */
+ public function setRatingStyle($value)
+ {
+ $this->setViewState('RatingStyle', $value, 'default');
+ }
+
+ /**
+ * @return TRatingListStyle current rating style
+ */
+ public function getRatingStyle()
+ {
+ return $this->getViewState('RatingStyle', 'default');
+ }
+
+ /**
+ * @return string rating style css class name.
+ */
+ protected function getRatingStyleCssClass()
+ {
+ return 'TRatingList_'.$this->getRatingStyle();
+ }
+
+ /**
+ * Sets the interval such that those rating values within the interval
+ * will be considered as a half star rating.
+ * @param array rating display half value interval, default is array(0.3, 0.7);
+ */
+ public function setHalfRatingInterval($value)
+ {
+ $this->setViewState('HalfRating',
+ TPropertyValue::ensureArray($value), array(0.3, 0.7));
+ }
+
+ /**
+ * @return array rating display half value interval, default is array(0.3, 0.7);
+ */
+ public function getHalfRatingInterval()
+ {
+ return $this->getViewState('HalfRating', array(0.3, 0.7));
+ }
+
+ /**
+ * @return array list of post back options.
+ */
+ protected function getPostBackOptions()
+ {
+ $options = parent::getPostBackOptions();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+ $options['ReadOnly'] = $this->getReadOnly();
+ $options['Style'] = $this->getRatingStyleCssClass();
+ $options['CaptionID'] = $this->getCaptionControlID();
+ $options['SelectedIndex'] = $this->getSelectedIndex();
+ $options['Rating'] = $this->getRating();
+ $options['HalfRating'] = $this->getHalfRatingInterval();
+ return $options;
+ }
+
+ /**
+ * @return string find the client ID of the caption control.
+ */
+ protected function getCaptionControlID()
+ {
+ if(($id=$this->getCaptionID())!=='')
+ {
+ if($control=$this->getParent()->findControl($id))
+ {
+ if($control->getVisible(true))
+ return $control->getClientID();
+ }
+ else
+ return $id;
+ }
+ return '';
+ }
+
+ /**
+ * Publish the the rating style css file and rating image files.
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+ $this->publishStyle($this->getRatingStyle());
+ $this->_ratingImages = $this->publishImages($this->getRatingStyle());
+ $this->registerClientScript();
+ }
+
+ /**
+ * @param string rating style name
+ * @return string URL of the css style file
+ */
+ protected function publishStyle($style)
+ {
+ $cs = $this->getPage()->getClientScript();
+ $url = $this->getAssetUrl($style.'.css');
+ if(!$cs->isStyleSheetFileRegistered($url))
+ $cs->registerStyleSheetFile($url, $url);
+ return $url;
+ }
+
+ /**
+ * @param string rating style name
+ * @param string rating image file extension, default is '.gif'
+ * @return array URL of publish the rating images
+ */
+ protected function publishImages($style, $fileExt='.gif')
+ {
+ $types = array('blank', 'selected', 'half', 'combined');
+ $files = array();
+ foreach($types as $type)
+ $files[$type] = $this->getAssetUrl("{$style}_{$type}{$fileExt}");
+ return $files;
+ }
+
+ /**
+ * Registers the relevant JavaScript.
+ */
+ protected function registerClientScript()
+ {
+ $cs=$this->getPage()->getClientScript();
+ $cs->registerPradoScript('ratings');
+ }
+
+ /**
+ * @param string asset file in the self::SCRIPT_PATH directory.
+ * @return string asset file url.
+ */
+ protected function getAssetUrl($file='')
+ {
+ $base = $this->getPage()->getClientScript()->getPradoScriptAssetUrl();
+ return $base.'/'.self::SCRIPT_PATH.'/'.$file;
+ }
+
+ /**
+ * Add rating style class name to the class attribute
+ * when {@link setReadOnly ReadOnly} property is true and when the
+ * {@link setCssClass CssClass} property is empty.
+ * @param THtmlWriter renderer
+ */
+ public function render($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $this->getPage()->getClientScript()->registerPostBackControl(
+ $this->getClientClassName(), $this->getPostBackOptions());
+ parent::render($writer);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRatingList';
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TReCaptcha.php b/framework/Web/UI/WebControls/TReCaptcha.php
index b9ba0070..cbdc2e36 100644
--- a/framework/Web/UI/WebControls/TReCaptcha.php
+++ b/framework/Web/UI/WebControls/TReCaptcha.php
@@ -1,233 +1,233 @@
-<?php
-
-/**
- * TReCaptcha class file
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @link http://www.devworx.hu/
- * @copyright Copyright &copy; 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
- Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
-
-/**
- * TReCaptcha class.
- *
- * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
- * to determine if the input is entered by a real user instead of some program. It can
- * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
- *
- * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
- * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
- * of the site you will need to register and get a public and a private API key pair, and
- * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey}
- * and {@link setPublicKey PublicKey} properties.
- *
- * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all
- * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
- * control on the page will lead to unpredictable results, and the user will most likely unable to solve
- * any of them successfully.
- *
- * Upon postback, user input can be validated by calling {@link validate()}.
- * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
- * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
- * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
- * input process, you must make sure that you call validate() only once, either at the end of the input process, or
- * you store the result till the end of the processing.
- *
- * The following template shows a typical use of TReCaptcha control:
- * <code>
- * <com:TReCaptcha ID="Captcha"
- * PublicKey="..."
- * PrivateKey="..."
- * />
- * <com:TReCaptchaValidator ControlToValidate="Captcha"
- * ErrorMessage="You are challenged!" />
- * </code>
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TReCaptcha extends TWebControl implements IValidatable
-{
- private $_isValid=true;
-
- const ChallengeFieldName = 'recaptcha_challenge_field';
- const ResponseFieldName = 'recaptcha_response_field';
-
- public function getTagName()
- {
- return 'span';
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- public function getValidationPropertyValue()
- {
- return $this->Request[$this->getChallengeFieldName()];
- }
-
- public function getPublicKey()
- {
- return $this->getViewState('PublicKey');
- }
-
- public function setPublicKey($value)
- {
- return $this->setViewState('PublicKey', TPropertyValue::ensureString($value));
- }
-
- public function getPrivateKey()
- {
- return $this->getViewState('PrivateKey');
- }
-
- public function setPrivateKey($value)
- {
- return $this->setViewState('PrivateKey', TPropertyValue::ensureString($value));
- }
-
- public function getThemeName()
- {
- return $this->getViewState('ThemeName');
- }
-
- public function setThemeName($value)
- {
- return $this->setViewState('ThemeName', TPropertyValue::ensureString($value));
- }
-
- public function getCustomTranslations()
- {
- return TPropertyValue::ensureArray($this->getViewState('CustomTranslations'));
- }
-
- public function setCustomTranslations($value)
- {
- return $this->setViewState('CustomTranslations', TPropertyValue::ensureArray($value));
- }
-
- public function getLanguage()
- {
- return $this->getViewState('Language');
- }
-
- public function setLanguage($value)
- {
- return $this->setViewState('Language', TPropertyValue::ensureString($value));
- }
-
- protected function getChallengeFieldName()
- {
- return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
- }
-
- public function getResponseFieldName()
- {
- return /*$this->ClientID.'_'.*/self::ResponseFieldName;
- }
-
- public function getClientSideOptions()
- {
- $options = array();
- if ($theme = $this->getThemeName())
- $options['theme'] = $theme;
- if ($lang = $this->getLanguage())
- $options['lang'] = $lang;
- if ($trans = $this->getCustomTranslations())
- $options['custom_translations'] = $trans;
- return $options;
- }
-
- public function validate()
- {
- if (!
- (
- ($challenge = @$_POST[$this->getChallengeFieldName()])
- and
- ($response = @$_POST[$this->getResponseFieldName()])
- )
- )
- return false;
-
- $resp = recaptcha_check_answer(
- $this->getPrivateKey(),
- $_SERVER["REMOTE_ADDR"],
- $challenge,
- $response
- );
- return ($resp->is_valid==1);
- }
-
- /**
- * Checks for API keys
- * @param mixed event parameter
- */
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- if("" == $this->getPublicKey())
- throw new TConfigurationException('recaptcha_publickey_unknown');
- if("" == $this->getPrivateKey())
- throw new TConfigurationException('recaptcha_privatekey_unknown');
-
- // need to register captcha fields so they will be sent back also in callbacks
- $page = $this->getPage();
- $page->registerRequiresPostData($this->getChallengeFieldName());
- $page->registerRequiresPostData($this->getResponseFieldName());
- }
-
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- }
-
- public function regenerateToken()
- {
- // if we're in a callback, then schedule re-rendering of the control
- // if not, don't do anything, because a new challenge will be rendered anyway
- if ($this->Page->IsCallback)
- $this->Page->ClientScript->registerEndScript($this->getClientID().'::refresh','Recaptcha.reload();');
- }
-
- public function renderContents($writer)
- {
- $writer->write(TJavaScript::renderScriptBlock(
- 'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';'
- ));
-
- $html = recaptcha_get_html($this->getPublicKey());
- /*
- reCAPTCHA currently does not support multiple validations per page
- $html = str_replace(
- array(self::ChallengeFieldName,self::ResponseFieldName),
- array($this->getChallengeFieldName(),$this->getResponseFieldName()),
- $html
- );
- */
- $writer->write($html);
- }
-
-}
-
+<?php
+
+/**
+ * TReCaptcha class file
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @link http://www.devworx.hu/
+ * @copyright Copyright &copy; 2011 DevWorx
+ * @license http://www.pradosoft.com/license/
+ * @package System.Web.UI.WebControls
+ */
+
+ Prado::using('System.3rdParty.ReCaptcha.recaptchalib');
+
+/**
+ * TReCaptcha class.
+ *
+ * TReCaptcha displays a reCAPTCHA (a token displayed as an image) that can be used
+ * to determine if the input is entered by a real user instead of some program. It can
+ * also prevent multiple submits of the same form either by accident, or on purpose (ie. spamming).
+ *
+ * The reCAPTCHA to solve (a string consisting of two separate words) displayed is automatically
+ * generated by the reCAPTCHA system at recaptcha.net. However, in order to use the services
+ * of the site you will need to register and get a public and a private API key pair, and
+ * supply those to the reCAPTCHA control through setting the {@link setPrivateKey PrivateKey}
+ * and {@link setPublicKey PublicKey} properties.
+ *
+ * Currently the reCAPTCHA API supports only one reCAPTCHA field per page, so you MUST make sure that all
+ * your input is protected and validated by a single reCAPTCHA control. Placing more than one reCAPTCHA
+ * control on the page will lead to unpredictable results, and the user will most likely unable to solve
+ * any of them successfully.
+ *
+ * Upon postback, user input can be validated by calling {@link validate()}.
+ * The {@link TReCaptchaValidator} control can also be used to do validation, which provides
+ * server-side validation. Calling (@link validate()) will invalidate the token supplied, so all consecutive
+ * calls to the method - without solving a new captcha - will return false. Therefore if implementing a multi-stage
+ * input process, you must make sure that you call validate() only once, either at the end of the input process, or
+ * you store the result till the end of the processing.
+ *
+ * The following template shows a typical use of TReCaptcha control:
+ * <code>
+ * <com:TReCaptcha ID="Captcha"
+ * PublicKey="..."
+ * PrivateKey="..."
+ * />
+ * <com:TReCaptchaValidator ControlToValidate="Captcha"
+ * ErrorMessage="You are challenged!" />
+ * </code>
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TReCaptcha extends TWebControl implements IValidatable
+{
+ private $_isValid=true;
+
+ const ChallengeFieldName = 'recaptcha_challenge_field';
+ const ResponseFieldName = 'recaptcha_response_field';
+
+ public function getTagName()
+ {
+ return 'span';
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ public function getValidationPropertyValue()
+ {
+ return $this->Request[$this->getChallengeFieldName()];
+ }
+
+ public function getPublicKey()
+ {
+ return $this->getViewState('PublicKey');
+ }
+
+ public function setPublicKey($value)
+ {
+ return $this->setViewState('PublicKey', TPropertyValue::ensureString($value));
+ }
+
+ public function getPrivateKey()
+ {
+ return $this->getViewState('PrivateKey');
+ }
+
+ public function setPrivateKey($value)
+ {
+ return $this->setViewState('PrivateKey', TPropertyValue::ensureString($value));
+ }
+
+ public function getThemeName()
+ {
+ return $this->getViewState('ThemeName');
+ }
+
+ public function setThemeName($value)
+ {
+ return $this->setViewState('ThemeName', TPropertyValue::ensureString($value));
+ }
+
+ public function getCustomTranslations()
+ {
+ return TPropertyValue::ensureArray($this->getViewState('CustomTranslations'));
+ }
+
+ public function setCustomTranslations($value)
+ {
+ return $this->setViewState('CustomTranslations', TPropertyValue::ensureArray($value));
+ }
+
+ public function getLanguage()
+ {
+ return $this->getViewState('Language');
+ }
+
+ public function setLanguage($value)
+ {
+ return $this->setViewState('Language', TPropertyValue::ensureString($value));
+ }
+
+ protected function getChallengeFieldName()
+ {
+ return /*$this->ClientID.'_'.*/self::ChallengeFieldName;
+ }
+
+ public function getResponseFieldName()
+ {
+ return /*$this->ClientID.'_'.*/self::ResponseFieldName;
+ }
+
+ public function getClientSideOptions()
+ {
+ $options = array();
+ if ($theme = $this->getThemeName())
+ $options['theme'] = $theme;
+ if ($lang = $this->getLanguage())
+ $options['lang'] = $lang;
+ if ($trans = $this->getCustomTranslations())
+ $options['custom_translations'] = $trans;
+ return $options;
+ }
+
+ public function validate()
+ {
+ if (!
+ (
+ ($challenge = @$_POST[$this->getChallengeFieldName()])
+ and
+ ($response = @$_POST[$this->getResponseFieldName()])
+ )
+ )
+ return false;
+
+ $resp = recaptcha_check_answer(
+ $this->getPrivateKey(),
+ $_SERVER["REMOTE_ADDR"],
+ $challenge,
+ $response
+ );
+ return ($resp->is_valid==1);
+ }
+
+ /**
+ * Checks for API keys
+ * @param mixed event parameter
+ */
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ if("" == $this->getPublicKey())
+ throw new TConfigurationException('recaptcha_publickey_unknown');
+ if("" == $this->getPrivateKey())
+ throw new TConfigurationException('recaptcha_privatekey_unknown');
+
+ // need to register captcha fields so they will be sent back also in callbacks
+ $page = $this->getPage();
+ $page->registerRequiresPostData($this->getChallengeFieldName());
+ $page->registerRequiresPostData($this->getResponseFieldName());
+ }
+
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ }
+
+ public function regenerateToken()
+ {
+ // if we're in a callback, then schedule re-rendering of the control
+ // if not, don't do anything, because a new challenge will be rendered anyway
+ if ($this->Page->IsCallback)
+ $this->Page->ClientScript->registerEndScript($this->getClientID().'::refresh','Recaptcha.reload();');
+ }
+
+ public function renderContents($writer)
+ {
+ $writer->write(TJavaScript::renderScriptBlock(
+ 'var RecaptchaOptions = '.TJavaScript::jsonEncode($this->getClientSideOptions()).';'
+ ));
+
+ $html = recaptcha_get_html($this->getPublicKey());
+ /*
+ reCAPTCHA currently does not support multiple validations per page
+ $html = str_replace(
+ array(self::ChallengeFieldName,self::ResponseFieldName),
+ array($this->getChallengeFieldName(),$this->getResponseFieldName()),
+ $html
+ );
+ */
+ $writer->write($html);
+ }
+
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TReCaptchaValidator.php b/framework/Web/UI/WebControls/TReCaptchaValidator.php
index 7199e401..41abbc5a 100644
--- a/framework/Web/UI/WebControls/TReCaptchaValidator.php
+++ b/framework/Web/UI/WebControls/TReCaptchaValidator.php
@@ -1,123 +1,123 @@
-<?php
-
-/**
- * TReCaptchaValidator class file
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @link http://www.devworx.hu/
- * @copyright Copyright &copy; 2011 DevWorx
- * @license http://www.pradosoft.com/license/
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-Prado::using('System.Web.UI.WebControls.TReCaptcha');
-
-/**
- * TReCaptchaValidator class
- *
- * TReCaptchaValidator validates user input against a reCAPTCHA represented by
- * a {@link TReCaptcha} control. The input control fails validation if its value
- * is not the same as the token displayed in reCAPTCHA. Note, if the user does
- * not enter any thing, it is still considered as failing the validation.
- *
- * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
- * to be the ID path of the {@link TReCaptcha} control.
- *
- * @author Bérczi Gábor <gabor.berczi@devworx.hu>
- * @package System.Web.UI.WebControls
- * @since 3.2
- */
-class TReCaptchaValidator extends TBaseValidator
-{
- protected $_isvalid = null;
-
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TReCaptchaValidator';
- }
-
- public function getEnableClientScript()
- {
- return true;
- }
-
- protected function getCaptchaControl()
- {
- $control = $this->getValidationTarget();
- if (!$control)
- throw new Exception('No target control specified for TReCaptchaValidator');
- if (!($control instanceof TReCaptcha))
- throw new Exception('TReCaptchaValidator only works with TReCaptcha controls');
- return $control;
- }
-
- public function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName();
- return $options;
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input control has the same value
- * as the one displayed in the corresponding RECAPTCHA control.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- // check validity only once (if trying to evaulate multiple times, all redundant checks would fail)
- if (is_null($this->_isvalid))
- {
- $control = $this->getCaptchaControl();
- $this->_isvalid = $control->validate();
- }
- return ($this->_isvalid==true);
- }
-
- public function onPreRender($param)
- {
- parent::onPreRender($param);
-
- $cs = $this->Page->getClientScript();
-
- // communicate validation status to the client side
- $value = $this->_isvalid===false ? '0' : '1';
- $cs->registerHiddenField($this->getClientID().'_1',$value);
-
- // check if we need to request a new captcha too
- if ($this->Page->IsCallback)
- {
- // force update of validator display
- if ($control = $this->getValidationTarget())
- {
- $cs->registerEndScript(
- $this->getClientID().'::validate',
- '$('.TJavaScript::quoteString($this->getClientID().'_1').').value = '.TJavaScript::quoteString($value).';'.
- 'Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).');'
- );
-
- if ($control->getVisible(true))
- if ($this->_isvalid)
- {
- // if the challenge has been solved + we're in a callback and we still reach prerender phase,
- // that means that some other validator failed and the user will be sent back to the page/form with
- // the captcha control. in this case we need to force re-rendering of the control, because once
- // solved, the old challenge won't validate anymore anyway
-
- $control->regenerateToken();
- }
- }
- }
- }
-
-}
-
+<?php
+
+/**
+ * TReCaptchaValidator class file
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @link http://www.devworx.hu/
+ * @copyright Copyright &copy; 2011 DevWorx
+ * @license http://www.pradosoft.com/license/
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+Prado::using('System.Web.UI.WebControls.TReCaptcha');
+
+/**
+ * TReCaptchaValidator class
+ *
+ * TReCaptchaValidator validates user input against a reCAPTCHA represented by
+ * a {@link TReCaptcha} control. The input control fails validation if its value
+ * is not the same as the token displayed in reCAPTCHA. Note, if the user does
+ * not enter any thing, it is still considered as failing the validation.
+ *
+ * To use TReCaptchaValidator, specify the {@link setControlToValidate ControlToValidate}
+ * to be the ID path of the {@link TReCaptcha} control.
+ *
+ * @author Bérczi Gábor <gabor.berczi@devworx.hu>
+ * @package System.Web.UI.WebControls
+ * @since 3.2
+ */
+class TReCaptchaValidator extends TBaseValidator
+{
+ protected $_isvalid = null;
+
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TReCaptchaValidator';
+ }
+
+ public function getEnableClientScript()
+ {
+ return true;
+ }
+
+ protected function getCaptchaControl()
+ {
+ $control = $this->getValidationTarget();
+ if (!$control)
+ throw new Exception('No target control specified for TReCaptchaValidator');
+ if (!($control instanceof TReCaptcha))
+ throw new Exception('TReCaptchaValidator only works with TReCaptcha controls');
+ return $control;
+ }
+
+ public function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['ResponseFieldName'] = $this->getCaptchaControl()->getResponseFieldName();
+ return $options;
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input control has the same value
+ * as the one displayed in the corresponding RECAPTCHA control.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ // check validity only once (if trying to evaulate multiple times, all redundant checks would fail)
+ if (is_null($this->_isvalid))
+ {
+ $control = $this->getCaptchaControl();
+ $this->_isvalid = $control->validate();
+ }
+ return ($this->_isvalid==true);
+ }
+
+ public function onPreRender($param)
+ {
+ parent::onPreRender($param);
+
+ $cs = $this->Page->getClientScript();
+
+ // communicate validation status to the client side
+ $value = $this->_isvalid===false ? '0' : '1';
+ $cs->registerHiddenField($this->getClientID().'_1',$value);
+
+ // check if we need to request a new captcha too
+ if ($this->Page->IsCallback)
+ {
+ // force update of validator display
+ if ($control = $this->getValidationTarget())
+ {
+ $cs->registerEndScript(
+ $this->getClientID().'::validate',
+ '$('.TJavaScript::quoteString($this->getClientID().'_1').').value = '.TJavaScript::quoteString($value).';'.
+ 'Prado.Validation.validateControl('.TJavaScript::quoteString($control->ClientID).');'
+ );
+
+ if ($control->getVisible(true))
+ if ($this->_isvalid)
+ {
+ // if the challenge has been solved + we're in a callback and we still reach prerender phase,
+ // that means that some other validator failed and the user will be sent back to the page/form with
+ // the captcha control. in this case we need to force re-rendering of the control, because once
+ // solved, the old challenge won't validate anymore anyway
+
+ $control->regenerateToken();
+ }
+ }
+ }
+ }
+
+}
+
?> \ No newline at end of file
diff --git a/framework/Web/UI/WebControls/TRegularExpressionValidator.php b/framework/Web/UI/WebControls/TRegularExpressionValidator.php
index a2a5bc64..0e85907a 100644
--- a/framework/Web/UI/WebControls/TRegularExpressionValidator.php
+++ b/framework/Web/UI/WebControls/TRegularExpressionValidator.php
@@ -1,144 +1,144 @@
-<?php
-/**
- * TRequiredFieldValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRegularExpressionValidator class
- *
- * TRegularExpressionValidator validates whether the value of an associated
- * input component matches the pattern specified by a regular expression.
- *
- * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression}
- * property. Some commonly used regular expressions include:
- * <pre>
- * French Phone Number: (0( \d|\d ))?\d\d \d\d(\d \d| \d\d )\d\d
- * French Postal Code: \d{5}
- * German Phone Number: ((\(0\d\d\) |(\(0\d{3}\) )?\d )?\d\d \d\d \d\d|\(0\d{4}\) \d \d\d-\d\d?)
- * German Postal Code: (D-)?\d{5}
- * Email Address: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
- * Japanese Phone Number: (0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4}
- * Japanese Postal Code: \d{3}(-(\d{4}|\d{2}))?
- * P.R.C. Phone Number: (\(\d{3}\)|\d{3}-)?\d{8}
- * P.R.C. Postal Code: \d{6}
- * P.R.C. Social Security Number: \d{18}|\d{15}
- * U.S. Phone Number: ((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}
- * U.S. ZIP Code: \d{5}(-\d{4})?
- * U.S. Social Security Number: \d{3}-\d{2}-\d{4}
- * </pre>
- *
- * Note, the validation succeeds if the associated input control contains empty input.
- * Use a {@link TRequiredFieldValidator} to ensure the input is not empty.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRegularExpressionValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRegularExpressionValidator';
- }
-
- /**
- * @return string the regular expression that determines the pattern used to validate a field.
- */
- public function getRegularExpression()
- {
- return $this->getViewState('RegularExpression','');
- }
-
- /**
- * @param string the regular expression that determines the pattern used to validate a field.
- */
- public function setRegularExpression($value)
- {
- $this->setViewState('RegularExpression',$value,'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input data matches the regular expression.
- * The validation always succeeds if ControlToValidate is not specified
- * or the regular expression is empty, or the input data is empty.
- * @return boolean whether the validation succeeds
- */
- public function evaluateIsValid()
- {
- if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
- return true;
- if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='')
- {
- $mods = $this->getPatternModifiers();
- return preg_match("/^$expression\$/{$mods}",$value);
- }
- else
- return true;
- }
-
- /**
- * @param string pattern modifiers for server side validation,
- * see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
- */
- public function setPatternModifiers($value)
- {
- $this->setViewState('PatternModifiers', $value);
- }
-
- /**
- * @return string pattern modifiers, no modifiers by default.
- */
- public function getPatternModifiers()
- {
- return $this->getViewState('PatternModifiers', '');
- }
-
- /**
- * @param string pattern modifiers for clientside.
- * (Only 'g','i' and 'm' are available.)
- */
- public function setClientSidePatternModifiers($value)
- {
- $this->setViewState('ClientSidePatternModifiers', $value);
- }
-
- /**
- * @return string clientside pattern modifiers, no modifiers by default.
- */
- public function getClientSidePatternModifiers()
- {
- return $this->getViewState('ClientSidePatternModifiers', '');
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['ValidationExpression']=$this->getRegularExpression();
- $options['PatternModifiers']=$this->getClientSidePatternModifiers();
- return $options;
- }
-}
-
+<?php
+/**
+ * TRequiredFieldValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRegularExpressionValidator class
+ *
+ * TRegularExpressionValidator validates whether the value of an associated
+ * input component matches the pattern specified by a regular expression.
+ *
+ * You can specify the regular expression by setting the {@link setRegularExpression RegularExpression}
+ * property. Some commonly used regular expressions include:
+ * <pre>
+ * French Phone Number: (0( \d|\d ))?\d\d \d\d(\d \d| \d\d )\d\d
+ * French Postal Code: \d{5}
+ * German Phone Number: ((\(0\d\d\) |(\(0\d{3}\) )?\d )?\d\d \d\d \d\d|\(0\d{4}\) \d \d\d-\d\d?)
+ * German Postal Code: (D-)?\d{5}
+ * Email Address: \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
+ * Japanese Phone Number: (0\d{1,4}-|\(0\d{1,4}\) ?)?\d{1,4}-\d{4}
+ * Japanese Postal Code: \d{3}(-(\d{4}|\d{2}))?
+ * P.R.C. Phone Number: (\(\d{3}\)|\d{3}-)?\d{8}
+ * P.R.C. Postal Code: \d{6}
+ * P.R.C. Social Security Number: \d{18}|\d{15}
+ * U.S. Phone Number: ((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}
+ * U.S. ZIP Code: \d{5}(-\d{4})?
+ * U.S. Social Security Number: \d{3}-\d{2}-\d{4}
+ * </pre>
+ *
+ * Note, the validation succeeds if the associated input control contains empty input.
+ * Use a {@link TRequiredFieldValidator} to ensure the input is not empty.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRegularExpressionValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRegularExpressionValidator';
+ }
+
+ /**
+ * @return string the regular expression that determines the pattern used to validate a field.
+ */
+ public function getRegularExpression()
+ {
+ return $this->getViewState('RegularExpression','');
+ }
+
+ /**
+ * @param string the regular expression that determines the pattern used to validate a field.
+ */
+ public function setRegularExpression($value)
+ {
+ $this->setViewState('RegularExpression',$value,'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input data matches the regular expression.
+ * The validation always succeeds if ControlToValidate is not specified
+ * or the regular expression is empty, or the input data is empty.
+ * @return boolean whether the validation succeeds
+ */
+ public function evaluateIsValid()
+ {
+ if(($value=$this->getValidationValue($this->getValidationTarget()))==='')
+ return true;
+ if(($expression=addcslashes($this->getRegularExpression(),"/"))!=='')
+ {
+ $mods = $this->getPatternModifiers();
+ return preg_match("/^$expression\$/{$mods}",$value);
+ }
+ else
+ return true;
+ }
+
+ /**
+ * @param string pattern modifiers for server side validation,
+ * see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
+ */
+ public function setPatternModifiers($value)
+ {
+ $this->setViewState('PatternModifiers', $value);
+ }
+
+ /**
+ * @return string pattern modifiers, no modifiers by default.
+ */
+ public function getPatternModifiers()
+ {
+ return $this->getViewState('PatternModifiers', '');
+ }
+
+ /**
+ * @param string pattern modifiers for clientside.
+ * (Only 'g','i' and 'm' are available.)
+ */
+ public function setClientSidePatternModifiers($value)
+ {
+ $this->setViewState('ClientSidePatternModifiers', $value);
+ }
+
+ /**
+ * @return string clientside pattern modifiers, no modifiers by default.
+ */
+ public function getClientSidePatternModifiers()
+ {
+ return $this->getViewState('ClientSidePatternModifiers', '');
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['ValidationExpression']=$this->getRegularExpression();
+ $options['PatternModifiers']=$this->getClientSidePatternModifiers();
+ return $options;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TRepeatInfo.php b/framework/Web/UI/WebControls/TRepeatInfo.php
index d7c6f0b6..2604e645 100644
--- a/framework/Web/UI/WebControls/TRepeatInfo.php
+++ b/framework/Web/UI/WebControls/TRepeatInfo.php
@@ -1,560 +1,560 @@
-<?php
-/**
- * IRepeatInfoUser, TRepeatInfo class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * IRepeatInfoUser, TRepeatInfo class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TTable');
-
-/**
- * IRepeatInfoUser interface.
- * This interface must be implemented by classes who want to use {@link TRepeatInfo}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-interface IRepeatInfoUser
-{
- /**
- * @return boolean whether the repeat user contains footer
- */
- public function getHasFooter();
- /**
- * @return boolean whether the repeat user contains header
- */
- public function getHasHeader();
- /**
- * @return boolean whether the repeat user contains separators
- */
- public function getHasSeparators();
- /**
- * @return integer number of items to be rendered (excluding header, footer and separators)
- */
- public function getItemCount();
- /**
- * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
- * @param integer zero-based index of the current rendering item.
- * @return TStyle CSS style used for rendering items (including header, footer and separators)
- */
- public function generateItemStyle($itemType,$index);
- /**
- * Renders an item.
- * @param THtmlWriter writer for the rendering purpose
- * @param TRepeatInfo repeat information
- * @param string item type
- * @param integer zero-based index of the item being rendered
- */
- public function renderItem($writer,$repeatInfo,$itemType,$index);
-}
-
-/**
- * TRepeatInfo class.
- * TRepeatInfo represents repeat information for controls like {@link TCheckBoxList}.
- * The layout of the repeated items is specified via {@link setRepeatLayout RepeatLayout},
- * which can be either Table (default), Flow or Raw.
- * A table layout uses HTML table cells to organize the items while
- * a flow layout uses line breaks to organize the items.
- * The number of columns used to display the items is specified via
- * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
- * governs the order of the items being rendered.
- *
- * Note, the Raw layout does not contain any formatting tags and thus ignores
- * the column and repeat direction settings.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeatInfo extends TComponent
-{
- /**
- * @var string caption of the table used to organize the repeated items
- */
- private $_caption='';
- /**
- * @var TTableCaptionAlign alignment of the caption of the table used to organize the repeated items
- */
- private $_captionAlign=TTableCaptionAlign::NotSet;
- /**
- * @var integer number of columns that the items should be arranged in
- */
- private $_repeatColumns=0;
- /**
- * @var TRepeatDirection direction of the repetition
- */
- private $_repeatDirection=TRepeatDirection::Vertical;
- /**
- * @var TRepeatLayout layout of the repeated items
- */
- private $_repeatLayout=TRepeatLayout::Table;
-
- /**
- * @return string caption of the table layout
- */
- public function getCaption()
- {
- return $this->_caption;
- }
-
- /**
- * @param string caption of the table layout
- */
- public function setCaption($value)
- {
- $this->_caption=$value;
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->_captionAlign;
- }
-
- /**
- * @return TTableCaptionAlign alignment of the caption of the table layout.
- */
- public function setCaptionAlign($value)
- {
- $this->_captionAlign=TPropertyValue::ensureEnum($value,'TTableCaptionAlign');
- }
-
- /**
- * @return integer the number of columns that the repeated items should be displayed in. Defaults to 0, meaning not set.
- */
- public function getRepeatColumns()
- {
- return $this->_repeatColumns;
- }
-
- /**
- * @param integer the number of columns that the repeated items should be displayed in.
- */
- public function setRepeatColumns($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('repeatinfo_repeatcolumns_invalid');
- $this->_repeatColumns=$value;
- }
-
- /**
- * @return TRepeatDirection the direction of traversing the repeated items, defaults to TRepeatDirection::Vertical
- */
- public function getRepeatDirection()
- {
- return $this->_repeatDirection;
- }
-
- /**
- * @param TRepeatDirection the direction of traversing the repeated items
- */
- public function setRepeatDirection($value)
- {
- $this->_repeatDirection=TPropertyValue::ensureEnum($value,'TRepeatDirection');
- }
-
- /**
- * @return TRepeatLayout how the repeated items should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
- */
- public function getRepeatLayout()
- {
- return $this->_repeatLayout;
- }
-
- /**
- * @param TRepeatLayout how the repeated items should be displayed, using table or using line breaks.
- */
- public function setRepeatLayout($value)
- {
- $this->_repeatLayout=TPropertyValue::ensureEnum($value,'TRepeatLayout');
- }
-
- /**
- * Renders the repeated items.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- public function renderRepeater($writer, IRepeatInfoUser $user)
- {
- if($this->_repeatLayout===TRepeatLayout::Table)
- {
- $control=new TTable;
- if($this->_caption!=='')
- {
- $control->setCaption($this->_caption);
- $control->setCaptionAlign($this->_captionAlign);
- }
- }
- else if($this->_repeatLayout===TRepeatLayout::Raw)
- {
- $this->renderRawContents($writer,$user);
- return;
- }
- else
- $control=new TWebControl;
- $control->setID($user->getClientID());
- $control->copyBaseAttributes($user);
- if($user->getHasStyle())
- $control->getStyle()->copyFrom($user->getStyle());
- $control->renderBeginTag($writer);
- $writer->writeLine();
-
- if($this->_repeatDirection===TRepeatDirection::Vertical)
- $this->renderVerticalContents($writer,$user);
- else
- $this->renderHorizontalContents($writer,$user);
-
- $control->renderEndTag($writer);
- }
-
- /**
- * Renders contents in raw format.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderRawContents($writer,$user)
- {
- if($user->getHasHeader())
- $user->renderItem($writer,$this,'Header',-1);
-
- // render items
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- for($i=0;$i<$itemCount;++$i)
- {
- $user->renderItem($writer,$this,'Item',$i);
- if($hasSeparators && $i!=$itemCount-1)
- $user->renderItem($writer,$this,'Separator',$i);
- }
- if($user->getHasFooter())
- $user->renderItem($writer,$this,'Footer',-1);
- }
-
- /**
- * Renders contents in horizontal repeat direction.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderHorizontalContents($writer,$user)
- {
- $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- $columns=$this->_repeatColumns===0?$itemCount:$this->_repeatColumns;
- $totalColumns=$hasSeparators?$columns+$columns:$columns;
- $needBreak=$columns<$itemCount;
-
- if($user->getHasHeader())
- $this->renderHeader($writer,$user,$tableLayout,$totalColumns,$needBreak);
-
- // render items
- if($tableLayout)
- {
- $writer->renderBeginTag('tbody');
- $column=0;
- for($i=0;$i<$itemCount;++$i)
- {
- if($column==0)
- $writer->renderBeginTag('tr');
- if(($style=$user->generateItemStyle('Item',$i))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Item',$i);
- $writer->renderEndTag();
- $writer->writeLine();
- if($hasSeparators && $i!=$itemCount-1)
- {
- if(($style=$user->generateItemStyle('Separator',$i))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Separator',$i);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- $column++;
- if($i==$itemCount-1)
- {
- $restColumns=$columns-$column;
- if($hasSeparators)
- $restColumns=$restColumns?$restColumns+$restColumns+1:1;
- for($j=0;$j<$restColumns;++$j)
- $writer->write("<td></td>\n");
- }
- if($column==$columns || $i==$itemCount-1)
- {
- $writer->renderEndTag();
- $writer->writeLine();
- $column=0;
- }
- }
- $writer->renderEndTag();
- }
- else
- {
- $column=0;
- for($i=0;$i<$itemCount;++$i)
- {
- $user->renderItem($writer,$this,'Item',$i);
- if($hasSeparators && $i!=$itemCount-1)
- $user->renderItem($writer,$this,'Separator',$i);
- $column++;
- if($column==$columns || $i==$itemCount-1)
- {
- if($needBreak)
- $writer->writeBreak();
- $column=0;
- }
- $writer->writeLine();
- }
- }
-
- if($user->getHasFooter())
- $this->renderFooter($writer,$user,$tableLayout,$totalColumns,$needBreak);
- }
-
- /**
- * Renders contents in veritcal repeat direction.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- */
- protected function renderVerticalContents($writer,$user)
- {
- $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
- $hasSeparators=$user->getHasSeparators();
- $itemCount=$user->getItemCount();
- if($this->_repeatColumns<=1)
- {
- $rows=$itemCount;
- $columns=1;
- $lastColumns=1;
- }
- else
- {
- $columns=$this->_repeatColumns;
- $rows=(int)(($itemCount+$columns-1)/$columns);
- if($rows==0 && $itemCount>0)
- $rows=1;
- if(($lastColumns=$itemCount%$columns)==0)
- $lastColumns=$columns;
- }
- $totalColumns=$hasSeparators?$columns+$columns:$columns;
-
- if($user->getHasHeader())
- $this->renderHeader($writer,$user,$tableLayout,$totalColumns,false);
-
- if($tableLayout)
- {
- $writer->renderBeginTag('tbody');
- $renderedItems=0;
- for($row=0;$row<$rows;++$row)
- {
- $index=$row;
- $writer->renderBeginTag('tr');
- for($col=0;$col<$columns;++$col)
- {
- if($renderedItems>=$itemCount)
- break;
- if($col>0)
- {
- $index+=$rows;
- if($col-1>=$lastColumns)
- $index--;
- }
- if($index>=$itemCount)
- continue;
- $renderedItems++;
- if(($style=$user->generateItemStyle('Item',$index))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Item',$index);
- $writer->renderEndTag();
- $writer->writeLine();
- if(!$hasSeparators)
- continue;
- if($renderedItems<$itemCount-1)
- {
- if($columns==1)
- {
- $writer->renderEndTag();
- $writer->renderBeginTag('tr');
- }
- if(($style=$user->generateItemStyle('Separator',$index))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Separator',$index);
- $writer->renderEndTag();
- $writer->writeLine();
- }
- else if($columns>1)
- $writer->write("<td></td>\n");
- }
- if($row==$rows-1)
- {
- $restColumns=$columns-$lastColumns;
- if($hasSeparators)
- $restColumns+=$restColumns;
- for($col=0;$col<$restColumns;++$col)
- $writer->write("<td></td>\n");
- }
- $writer->renderEndTag();
- $writer->writeLine();
- }
- $writer->renderEndTag();
- }
- else
- {
- $renderedItems=0;
- for($row=0;$row<$rows;++$row)
- {
- $index=$row;
- for($col=0;$col<$columns;++$col)
- {
- if($renderedItems>=$itemCount)
- break;
- if($col>0)
- {
- $index+=$rows;
- if($col-1>=$lastColumns)
- $index--;
- }
- if($index>=$itemCount)
- continue;
- $renderedItems++;
- $user->renderItem($writer,$this,'Item',$index);
- $writer->writeLine();
- if(!$hasSeparators)
- continue;
- if($renderedItems<$itemCount-1)
- {
- if($columns==1)
- $writer->writeBreak();
- $user->renderItem($writer,$this,'Separator',$index);
- }
- $writer->writeLine();
- }
- if($row<$rows-1 || $user->getHasFooter())
- $writer->writeBreak();
- }
- }
-
- if($user->getHasFooter())
- $this->renderFooter($writer,$user,$tableLayout,$totalColumns,false);
-
- }
-
- /**
- * Renders header.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- * @param boolean whether to render using table layout
- * @param integer number of columns to be rendered
- * @param boolean if a line break is needed at the end
- */
- protected function renderHeader($writer,$user,$tableLayout,$columns,$needBreak)
- {
- if($tableLayout)
- {
- $writer->renderBeginTag('thead');
- $writer->renderBeginTag('tr');
- if($columns>1)
- $writer->addAttribute('colspan',"$columns");
- $writer->addAttribute('scope','col');
- if(($style=$user->generateItemStyle('Header',-1))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('th');
- $user->renderItem($writer,$this,'Header',-1);
- $writer->renderEndTag();
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
- else
- {
- $user->renderItem($writer,$this,'Header',-1);
- if($needBreak)
- $writer->writeBreak();
- }
- $writer->writeLine();
- }
-
- /**
- * Renders footer.
- * @param THtmlWriter writer for the rendering purpose
- * @param IRepeatInfoUser repeat information user
- * @param boolean whether to render using table layout
- * @param integer number of columns to be rendered
- */
- protected function renderFooter($writer,$user,$tableLayout,$columns)
- {
- if($tableLayout)
- {
- $writer->renderBeginTag('tfoot');
- $writer->renderBeginTag('tr');
- if($columns>1)
- $writer->addAttribute('colspan',"$columns");
- if(($style=$user->generateItemStyle('Footer',-1))!==null)
- $style->addAttributesToRender($writer);
- $writer->renderBeginTag('td');
- $user->renderItem($writer,$this,'Footer',-1);
- $writer->renderEndTag();
- $writer->renderEndTag();
- $writer->renderEndTag();
- }
- else
- $user->renderItem($writer,$this,'Footer',-1);
- $writer->writeLine();
- }
-}
-
-
-/**
- * TRepeatDirection class.
- * TRepeatDirection defines the enumerable type for the possible directions
- * that repeated contents can repeat along
- *
- * The following enumerable values are defined:
- * - Vertical
- * - Horizontal
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRepeatDirection extends TEnumerable
-{
- const Vertical='Vertical';
- const Horizontal='Horizontal';
-}
-
-/**
- * TRepeatLayout class.
- * TRepeatLayout defines the enumerable type for the possible layouts
- * that repeated contents can take.
- *
- * The following enumerable values are defined:
- * - Table: the repeated contents are organized using an HTML table
- * - Flow: the repeated contents are organized using HTML spans and breaks
- * - Raw: the repeated contents are stacked together without any additional decorations
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TRepeatLayout extends TEnumerable
-{
- const Table='Table';
- const Flow='Flow';
- const Raw='Raw';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TTable');
+
+/**
+ * IRepeatInfoUser interface.
+ * This interface must be implemented by classes who want to use {@link TRepeatInfo}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+interface IRepeatInfoUser
+{
+ /**
+ * @return boolean whether the repeat user contains footer
+ */
+ public function getHasFooter();
+ /**
+ * @return boolean whether the repeat user contains header
+ */
+ public function getHasHeader();
+ /**
+ * @return boolean whether the repeat user contains separators
+ */
+ public function getHasSeparators();
+ /**
+ * @return integer number of items to be rendered (excluding header, footer and separators)
+ */
+ public function getItemCount();
+ /**
+ * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
+ * @param integer zero-based index of the current rendering item.
+ * @return TStyle CSS style used for rendering items (including header, footer and separators)
+ */
+ public function generateItemStyle($itemType,$index);
+ /**
+ * Renders an item.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param TRepeatInfo repeat information
+ * @param string item type
+ * @param integer zero-based index of the item being rendered
+ */
+ public function renderItem($writer,$repeatInfo,$itemType,$index);
+}
+
+/**
+ * TRepeatInfo class.
+ * TRepeatInfo represents repeat information for controls like {@link TCheckBoxList}.
+ * The layout of the repeated items is specified via {@link setRepeatLayout RepeatLayout},
+ * which can be either Table (default), Flow or Raw.
+ * A table layout uses HTML table cells to organize the items while
+ * a flow layout uses line breaks to organize the items.
+ * The number of columns used to display the items is specified via
+ * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
+ * governs the order of the items being rendered.
+ *
+ * Note, the Raw layout does not contain any formatting tags and thus ignores
+ * the column and repeat direction settings.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeatInfo extends TComponent
+{
+ /**
+ * @var string caption of the table used to organize the repeated items
+ */
+ private $_caption='';
+ /**
+ * @var TTableCaptionAlign alignment of the caption of the table used to organize the repeated items
+ */
+ private $_captionAlign=TTableCaptionAlign::NotSet;
+ /**
+ * @var integer number of columns that the items should be arranged in
+ */
+ private $_repeatColumns=0;
+ /**
+ * @var TRepeatDirection direction of the repetition
+ */
+ private $_repeatDirection=TRepeatDirection::Vertical;
+ /**
+ * @var TRepeatLayout layout of the repeated items
+ */
+ private $_repeatLayout=TRepeatLayout::Table;
+
+ /**
+ * @return string caption of the table layout
+ */
+ public function getCaption()
+ {
+ return $this->_caption;
+ }
+
+ /**
+ * @param string caption of the table layout
+ */
+ public function setCaption($value)
+ {
+ $this->_caption=$value;
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->_captionAlign;
+ }
+
+ /**
+ * @return TTableCaptionAlign alignment of the caption of the table layout.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->_captionAlign=TPropertyValue::ensureEnum($value,'TTableCaptionAlign');
+ }
+
+ /**
+ * @return integer the number of columns that the repeated items should be displayed in. Defaults to 0, meaning not set.
+ */
+ public function getRepeatColumns()
+ {
+ return $this->_repeatColumns;
+ }
+
+ /**
+ * @param integer the number of columns that the repeated items should be displayed in.
+ */
+ public function setRepeatColumns($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('repeatinfo_repeatcolumns_invalid');
+ $this->_repeatColumns=$value;
+ }
+
+ /**
+ * @return TRepeatDirection the direction of traversing the repeated items, defaults to TRepeatDirection::Vertical
+ */
+ public function getRepeatDirection()
+ {
+ return $this->_repeatDirection;
+ }
+
+ /**
+ * @param TRepeatDirection the direction of traversing the repeated items
+ */
+ public function setRepeatDirection($value)
+ {
+ $this->_repeatDirection=TPropertyValue::ensureEnum($value,'TRepeatDirection');
+ }
+
+ /**
+ * @return TRepeatLayout how the repeated items should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
+ */
+ public function getRepeatLayout()
+ {
+ return $this->_repeatLayout;
+ }
+
+ /**
+ * @param TRepeatLayout how the repeated items should be displayed, using table or using line breaks.
+ */
+ public function setRepeatLayout($value)
+ {
+ $this->_repeatLayout=TPropertyValue::ensureEnum($value,'TRepeatLayout');
+ }
+
+ /**
+ * Renders the repeated items.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ public function renderRepeater($writer, IRepeatInfoUser $user)
+ {
+ if($this->_repeatLayout===TRepeatLayout::Table)
+ {
+ $control=new TTable;
+ if($this->_caption!=='')
+ {
+ $control->setCaption($this->_caption);
+ $control->setCaptionAlign($this->_captionAlign);
+ }
+ }
+ else if($this->_repeatLayout===TRepeatLayout::Raw)
+ {
+ $this->renderRawContents($writer,$user);
+ return;
+ }
+ else
+ $control=new TWebControl;
+ $control->setID($user->getClientID());
+ $control->copyBaseAttributes($user);
+ if($user->getHasStyle())
+ $control->getStyle()->copyFrom($user->getStyle());
+ $control->renderBeginTag($writer);
+ $writer->writeLine();
+
+ if($this->_repeatDirection===TRepeatDirection::Vertical)
+ $this->renderVerticalContents($writer,$user);
+ else
+ $this->renderHorizontalContents($writer,$user);
+
+ $control->renderEndTag($writer);
+ }
+
+ /**
+ * Renders contents in raw format.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderRawContents($writer,$user)
+ {
+ if($user->getHasHeader())
+ $user->renderItem($writer,$this,'Header',-1);
+
+ // render items
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ for($i=0;$i<$itemCount;++$i)
+ {
+ $user->renderItem($writer,$this,'Item',$i);
+ if($hasSeparators && $i!=$itemCount-1)
+ $user->renderItem($writer,$this,'Separator',$i);
+ }
+ if($user->getHasFooter())
+ $user->renderItem($writer,$this,'Footer',-1);
+ }
+
+ /**
+ * Renders contents in horizontal repeat direction.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderHorizontalContents($writer,$user)
+ {
+ $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ $columns=$this->_repeatColumns===0?$itemCount:$this->_repeatColumns;
+ $totalColumns=$hasSeparators?$columns+$columns:$columns;
+ $needBreak=$columns<$itemCount;
+
+ if($user->getHasHeader())
+ $this->renderHeader($writer,$user,$tableLayout,$totalColumns,$needBreak);
+
+ // render items
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tbody');
+ $column=0;
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($column==0)
+ $writer->renderBeginTag('tr');
+ if(($style=$user->generateItemStyle('Item',$i))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Item',$i);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ if($hasSeparators && $i!=$itemCount-1)
+ {
+ if(($style=$user->generateItemStyle('Separator',$i))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Separator',$i);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ $column++;
+ if($i==$itemCount-1)
+ {
+ $restColumns=$columns-$column;
+ if($hasSeparators)
+ $restColumns=$restColumns?$restColumns+$restColumns+1:1;
+ for($j=0;$j<$restColumns;++$j)
+ $writer->write("<td></td>\n");
+ }
+ if($column==$columns || $i==$itemCount-1)
+ {
+ $writer->renderEndTag();
+ $writer->writeLine();
+ $column=0;
+ }
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $column=0;
+ for($i=0;$i<$itemCount;++$i)
+ {
+ $user->renderItem($writer,$this,'Item',$i);
+ if($hasSeparators && $i!=$itemCount-1)
+ $user->renderItem($writer,$this,'Separator',$i);
+ $column++;
+ if($column==$columns || $i==$itemCount-1)
+ {
+ if($needBreak)
+ $writer->writeBreak();
+ $column=0;
+ }
+ $writer->writeLine();
+ }
+ }
+
+ if($user->getHasFooter())
+ $this->renderFooter($writer,$user,$tableLayout,$totalColumns,$needBreak);
+ }
+
+ /**
+ * Renders contents in veritcal repeat direction.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ */
+ protected function renderVerticalContents($writer,$user)
+ {
+ $tableLayout=($this->_repeatLayout===TRepeatLayout::Table);
+ $hasSeparators=$user->getHasSeparators();
+ $itemCount=$user->getItemCount();
+ if($this->_repeatColumns<=1)
+ {
+ $rows=$itemCount;
+ $columns=1;
+ $lastColumns=1;
+ }
+ else
+ {
+ $columns=$this->_repeatColumns;
+ $rows=(int)(($itemCount+$columns-1)/$columns);
+ if($rows==0 && $itemCount>0)
+ $rows=1;
+ if(($lastColumns=$itemCount%$columns)==0)
+ $lastColumns=$columns;
+ }
+ $totalColumns=$hasSeparators?$columns+$columns:$columns;
+
+ if($user->getHasHeader())
+ $this->renderHeader($writer,$user,$tableLayout,$totalColumns,false);
+
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tbody');
+ $renderedItems=0;
+ for($row=0;$row<$rows;++$row)
+ {
+ $index=$row;
+ $writer->renderBeginTag('tr');
+ for($col=0;$col<$columns;++$col)
+ {
+ if($renderedItems>=$itemCount)
+ break;
+ if($col>0)
+ {
+ $index+=$rows;
+ if($col-1>=$lastColumns)
+ $index--;
+ }
+ if($index>=$itemCount)
+ continue;
+ $renderedItems++;
+ if(($style=$user->generateItemStyle('Item',$index))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Item',$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ if(!$hasSeparators)
+ continue;
+ if($renderedItems<$itemCount-1)
+ {
+ if($columns==1)
+ {
+ $writer->renderEndTag();
+ $writer->renderBeginTag('tr');
+ }
+ if(($style=$user->generateItemStyle('Separator',$index))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Separator',$index);
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ else if($columns>1)
+ $writer->write("<td></td>\n");
+ }
+ if($row==$rows-1)
+ {
+ $restColumns=$columns-$lastColumns;
+ if($hasSeparators)
+ $restColumns+=$restColumns;
+ for($col=0;$col<$restColumns;++$col)
+ $writer->write("<td></td>\n");
+ }
+ $writer->renderEndTag();
+ $writer->writeLine();
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $renderedItems=0;
+ for($row=0;$row<$rows;++$row)
+ {
+ $index=$row;
+ for($col=0;$col<$columns;++$col)
+ {
+ if($renderedItems>=$itemCount)
+ break;
+ if($col>0)
+ {
+ $index+=$rows;
+ if($col-1>=$lastColumns)
+ $index--;
+ }
+ if($index>=$itemCount)
+ continue;
+ $renderedItems++;
+ $user->renderItem($writer,$this,'Item',$index);
+ $writer->writeLine();
+ if(!$hasSeparators)
+ continue;
+ if($renderedItems<$itemCount-1)
+ {
+ if($columns==1)
+ $writer->writeBreak();
+ $user->renderItem($writer,$this,'Separator',$index);
+ }
+ $writer->writeLine();
+ }
+ if($row<$rows-1 || $user->getHasFooter())
+ $writer->writeBreak();
+ }
+ }
+
+ if($user->getHasFooter())
+ $this->renderFooter($writer,$user,$tableLayout,$totalColumns,false);
+
+ }
+
+ /**
+ * Renders header.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ * @param boolean whether to render using table layout
+ * @param integer number of columns to be rendered
+ * @param boolean if a line break is needed at the end
+ */
+ protected function renderHeader($writer,$user,$tableLayout,$columns,$needBreak)
+ {
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('thead');
+ $writer->renderBeginTag('tr');
+ if($columns>1)
+ $writer->addAttribute('colspan',"$columns");
+ $writer->addAttribute('scope','col');
+ if(($style=$user->generateItemStyle('Header',-1))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('th');
+ $user->renderItem($writer,$this,'Header',-1);
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $user->renderItem($writer,$this,'Header',-1);
+ if($needBreak)
+ $writer->writeBreak();
+ }
+ $writer->writeLine();
+ }
+
+ /**
+ * Renders footer.
+ * @param THtmlWriter writer for the rendering purpose
+ * @param IRepeatInfoUser repeat information user
+ * @param boolean whether to render using table layout
+ * @param integer number of columns to be rendered
+ */
+ protected function renderFooter($writer,$user,$tableLayout,$columns)
+ {
+ if($tableLayout)
+ {
+ $writer->renderBeginTag('tfoot');
+ $writer->renderBeginTag('tr');
+ if($columns>1)
+ $writer->addAttribute('colspan',"$columns");
+ if(($style=$user->generateItemStyle('Footer',-1))!==null)
+ $style->addAttributesToRender($writer);
+ $writer->renderBeginTag('td');
+ $user->renderItem($writer,$this,'Footer',-1);
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ $writer->renderEndTag();
+ }
+ else
+ $user->renderItem($writer,$this,'Footer',-1);
+ $writer->writeLine();
+ }
+}
+
+
+/**
+ * TRepeatDirection class.
+ * TRepeatDirection defines the enumerable type for the possible directions
+ * that repeated contents can repeat along
+ *
+ * The following enumerable values are defined:
+ * - Vertical
+ * - Horizontal
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRepeatDirection extends TEnumerable
+{
+ const Vertical='Vertical';
+ const Horizontal='Horizontal';
+}
+
+/**
+ * TRepeatLayout class.
+ * TRepeatLayout defines the enumerable type for the possible layouts
+ * that repeated contents can take.
+ *
+ * The following enumerable values are defined:
+ * - Table: the repeated contents are organized using an HTML table
+ * - Flow: the repeated contents are organized using HTML spans and breaks
+ * - Raw: the repeated contents are stacked together without any additional decorations
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TRepeatLayout extends TEnumerable
+{
+ const Table='Table';
+ const Flow='Flow';
+ const Raw='Raw';
+}
+
diff --git a/framework/Web/UI/WebControls/TRepeater.php b/framework/Web/UI/WebControls/TRepeater.php
index 6a59cbab..944b3a17 100644
--- a/framework/Web/UI/WebControls/TRepeater.php
+++ b/framework/Web/UI/WebControls/TRepeater.php
@@ -1,1025 +1,1025 @@
-<?php
-/**
- * TRepeater class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TRepeater class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TDataBoundControl and TDataFieldAccessor cass
- */
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Util.TDataFieldAccessor');
-
-/**
- * TRepeater class.
- *
- * TRepeater displays its content repeatedly based on the data fetched from
- * {@link setDataSource DataSource}.
- * The repeated contents in TRepeater are called items, which are controls and
- * can be accessed through {@link getItems Items}. When {@link dataBind()} is invoked,
- * TRepeater creates an item for each row of data and binds the data row to the item.
- * Optionally, a repeater can have a header, a footer and/or separators between items.
- *
- * The layout of the repeated contents are specified by inline templates.
- * Repeater items, header, footer, etc. are being instantiated with the corresponding
- * templates when data is being bound to the repeater.
- *
- * Since v3.1.0, the layout can also be specified by renderers. A renderer is a control class
- * that can be instantiated as repeater items, header, etc. A renderer can thus be viewed
- * as an external template (in fact, it can also be non-templated controls).
- *
- * A renderer can be any control class.
- * - If the class implements {@link IDataRenderer}, the <b>Data</b>
- * property will be set as the data row during databinding. Many PRADO controls
- * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
- * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
- * as the zero-based index of the item in the repeater item collection, and
- * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
- * {@link TRepeaterItemRenderer} may be used as the convenient base class which
- * already implements {@link IDataItemRenderer}.
- *
- * The following properties are used to specify different types of template and renderer
- * for a repeater:
- * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
- * for each repeated row of data
- * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
- * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
- * will be used instead.
- * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
- * for the repeater header.
- * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
- * for the repeater footer.
- * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
- * for content to be displayed between items.
- * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
- * used when data bound to the repeater is empty.
- *
- * If a content type is defined with both a template and a renderer, the latter takes precedence.
- *
- * When {@link dataBind()} is being called, TRepeater undergoes the following lifecycles for each row of data:
- * - create item based on templates or renderers
- * - set the row of data to the item
- * - raise {@link onItemCreated OnItemCreated}:
- * - add the item as a child control
- * - call dataBind() of the item
- * - raise {@link onItemDataBound OnItemDataBound}:
- *
- * TRepeater raises an {@link onItemCommand OnItemCommand} whenever a button control
- * within some repeater item raises a <b>OnCommand</b> event. Therefore,
- * you can handle all sorts of <b>OnCommand</b> event in a central place by
- * writing an event handler for {@link onItemCommand OnItemCommand}.
- *
- * When a page containing a repeater is post back, the repeater will restore automatically
- * all its contents, including items, header, footer and separators.
- * However, the data row associated with each item will not be recovered and become null.
- * To access the data, use one of the following ways:
- * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
- * the specified repeater item and use the key to fetch the corresponding data
- * from some persistent storage such as DB.
- * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
- * Be aware though, if the size of your dataset is big, your page size will become big. Some
- * complex data may also have serializing problem if saved in viewstate.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeater extends TDataBoundControl implements INamingContainer
-{
- /**
- * Repeater item types
- * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
- */
- const IT_HEADER='Header';
- const IT_FOOTER='Footer';
- const IT_ITEM='Item';
- const IT_SEPARATOR='Separator';
- const IT_ALTERNATINGITEM='AlternatingItem';
-
- /**
- * @var ITemplate template for repeater items
- */
- private $_itemTemplate=null;
- /**
- * @var ITemplate template for each alternating item
- */
- private $_alternatingItemTemplate=null;
- /**
- * @var ITemplate template for header
- */
- private $_headerTemplate=null;
- /**
- * @var ITemplate template for footer
- */
- private $_footerTemplate=null;
- /**
- * @var ITemplate template used for repeater when no data is bound
- */
- private $_emptyTemplate=null;
- /**
- * @var ITemplate template for separator
- */
- private $_separatorTemplate=null;
- /**
- * @var TRepeaterItemCollection list of repeater items
- */
- private $_items=null;
- /**
- * @var TControl header item
- */
- private $_header=null;
- /**
- * @var TControl footer item
- */
- private $_footer=null;
-
-
- /**
- * @return string the class name for repeater items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater items.
- * This property takes precedence over {@link getItemTemplate ItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setItemTemplate
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for alternative repeater items. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getAlternatingItemRenderer()
- {
- return $this->getViewState('AlternatingItemRenderer','');
- }
-
- /**
- * Sets the alternative item renderer class.
- *
- * If not empty, the class will be used to instantiate as alternative repeater items.
- * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setAlternatingItemTemplate
- * @since 3.1.0
- */
- public function setAlternatingItemRenderer($value)
- {
- $this->setViewState('AlternatingItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater item separators. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getSeparatorRenderer()
- {
- return $this->getViewState('SeparatorRenderer','');
- }
-
- /**
- * Sets the repeater item separator renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater item separators.
- * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setSeparatorTemplate
- * @since 3.1.0
- */
- public function setSeparatorRenderer($value)
- {
- $this->setViewState('SeparatorRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater header item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getHeaderRenderer()
- {
- return $this->getViewState('HeaderRenderer','');
- }
-
- /**
- * Sets the repeater header renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater header item.
- * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setHeaderTemplate
- * @since 3.1.0
- */
- public function setHeaderRenderer($value)
- {
- $this->setViewState('HeaderRenderer',$value,'');
- }
-
- /**
- * @return string the class name for repeater footer item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getFooterRenderer()
- {
- return $this->getViewState('FooterRenderer','');
- }
-
- /**
- * Sets the repeater footer renderer class.
- *
- * If not empty, the class will be used to instantiate as repeater footer item.
- * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setFooterTemplate
- * @since 3.1.0
- */
- public function setFooterRenderer($value)
- {
- $this->setViewState('FooterRenderer',$value,'');
- }
-
- /**
- * @return string the class name for empty repeater item. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEmptyRenderer()
- {
- return $this->getViewState('EmptyRenderer','');
- }
-
- /**
- * Sets the repeater empty renderer class.
- *
- * The empty renderer is created as the child of the repeater
- * if data bound to the repeater is empty.
- * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
- *
- * @param string the renderer class name in namespace format.
- * @see setEmptyTemplate
- * @since 3.1.0
- */
- public function setEmptyRenderer($value)
- {
- $this->setViewState('EmptyRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the template for repeater items
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the template for repeater items
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','ItemTemplate');
- }
-
- /**
- * @return ITemplate the alternative template string for the item
- */
- public function getAlternatingItemTemplate()
- {
- return $this->_alternatingItemTemplate;
- }
-
- /**
- * @param ITemplate the alternative item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setAlternatingItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_alternatingItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','AlternatingItemTemplate');
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','HeaderTemplate');
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','FooterTemplate');
- }
-
- /**
- * @return ITemplate the template applied when no data is bound to the repeater
- */
- public function getEmptyTemplate()
- {
- return $this->_emptyTemplate;
- }
-
- /**
- * @param ITemplate the template applied when no data is bound to the repeater
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEmptyTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_emptyTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','EmptyTemplate');
- }
-
- /**
- * @return ITemplate the separator template
- */
- public function getSeparatorTemplate()
- {
- return $this->_separatorTemplate;
- }
-
- /**
- * @param ITemplate the separator template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setSeparatorTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_separatorTemplate=$value;
- else
- throw new TInvalidDataTypeException('repeater_template_required','SeparatorTemplate');
- }
-
- /**
- * @return TControl the header item
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TControl the footer item
- */
- public function getFooter()
- {
- return $this->_footer;
- }
-
- /**
- * @return TRepeaterItemCollection list of repeater item controls
- */
- public function getItems()
- {
- if(!$this->_items)
- $this->_items=new TRepeaterItemCollection;
- return $this->_items;
- }
-
- /**
- * @return string the field of the data source that provides the keys of the list items.
- */
- public function getDataKeyField()
- {
- return $this->getViewState('DataKeyField','');
- }
-
- /**
- * @param string the field of the data source that provides the keys of the list items.
- */
- public function setDataKeyField($value)
- {
- $this->setViewState('DataKeyField',$value,'');
- }
-
- /**
- * @return TList the keys used in the data listing control.
- */
- public function getDataKeys()
- {
- if(($dataKeys=$this->getViewState('DataKeys',null))===null)
- {
- $dataKeys=new TList;
- $this->setViewState('DataKeys',$dataKeys,null);
- }
- return $dataKeys;
- }
-
- /**
- * Creates a repeater item.
- * This method invokes {@link createItem} to create a new repeater item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @return TControl the created item, null if item is not created
- */
- private function createItemInternal($itemIndex,$itemType)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TRepeaterItemEventParameter($item);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a repeater item and performs databinding.
- * This method invokes {@link createItem} to create a new repeater item.
- * @param integer zero-based item index.
- * @param TListItemType item type
- * @param mixed data to be associated with the item
- * @return TControl the created item, null if item is not created
- */
- private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
- {
- if(($item=$this->createItem($itemIndex,$itemType))!==null)
- {
- $param=new TRepeaterItemEventParameter($item);
- if($item instanceof IDataRenderer)
- $item->setData($dataItem);
- $this->onItemCreated($param);
- $this->getControls()->add($item);
- $item->dataBind();
- $this->onItemDataBound($param);
- return $item;
- }
- else
- return null;
- }
-
- /**
- * Creates a repeater item instance based on the item type and index.
- * @param integer zero-based item index
- * @param TListItemType item type
- * @return TControl created repeater item
- */
- protected function createItem($itemIndex,$itemType)
- {
- $template=null;
- $classPath=null;
- switch($itemType)
- {
- case TListItemType::Item :
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- break;
- case TListItemType::AlternatingItem :
- if(($classPath=$this->getAlternatingItemRenderer())==='' && ($template=$this->_alternatingItemTemplate)===null)
- {
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- }
- break;
- case TListItemType::Header :
- $classPath=$this->getHeaderRenderer();
- $template=$this->_headerTemplate;
- break;
- case TListItemType::Footer :
- $classPath=$this->getFooterRenderer();
- $template=$this->_footerTemplate;
- break;
- case TListItemType::Separator :
- $classPath=$this->getSeparatorRenderer();
- $template=$this->_separatorTemplate;
- break;
- default:
- throw new TInvalidDataValueException('repeater_itemtype_unknown',$itemType);
- }
- if($classPath!=='')
- {
- $item=Prado::createComponent($classPath);
- if($item instanceof IItemDataRenderer)
- {
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- }
- }
- else if($template!==null)
- {
- $item=new TRepeaterItem;
- $item->setItemIndex($itemIndex);
- $item->setItemType($itemType);
- $template->instantiateIn($item);
- }
- else
- $item=null;
-
- return $item;
- }
-
- /**
- * Creates empty repeater content.
- */
- protected function createEmptyContent()
- {
- if(($classPath=$this->getEmptyRenderer())!=='')
- $this->getControls()->add(Prado::createComponent($classPath));
- else if($this->_emptyTemplate!==null)
- $this->_emptyTemplate->instantiateIn($this);
- }
-
- /**
- * Renders the repeater.
- * This method overrides the parent implementation by rendering the body
- * content as the whole presentation of the repeater. Outer tag is not rendered.
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- if($this->_items && $this->_items->getCount() || $this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
- $this->renderContents($writer);
- }
-
- /**
- * Saves item count in viewstate.
- * This method is invoked right before control state is to be saved.
- */
- public function saveState()
- {
- parent::saveState();
- if($this->_items)
- $this->setViewState('ItemCount',$this->_items->getCount(),0);
- else
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Loads item count information from viewstate.
- * This method is invoked right after control state is loaded.
- */
- public function loadState()
- {
- parent::loadState();
- if(!$this->getIsDataBound())
- $this->restoreItemsFromViewState();
- $this->clearViewState('ItemCount');
- }
-
- /**
- * Clears up all items in the repeater.
- */
- public function reset()
- {
- $this->getControls()->clear();
- $this->getItems()->clear();
- $this->_header=null;
- $this->_footer=null;
- }
-
- /**
- * Creates repeater items based on viewstate information.
- */
- protected function restoreItemsFromViewState()
- {
- $this->reset();
- if(($itemCount=$this->getViewState('ItemCount',0))>0)
- {
- $items=$this->getItems();
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- $this->_header=$this->createItemInternal(-1,TListItemType::Header);
- for($i=0;$i<$itemCount;++$i)
- {
- if($hasSeparator && $i>0)
- $this->createItemInternal($i-1,TListItemType::Separator);
- $itemType=$i%2==0?TListItemType::Item : TListItemType::AlternatingItem;
- $items->add($this->createItemInternal($i,$itemType,false,null));
- }
- $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
- }
- else
- $this->createEmptyContent();
- $this->clearChildState();
- }
-
- /**
- * Performs databinding to populate repeater items from data source.
- * This method is invoked by dataBind().
- * You may override this function to provide your own way of data population.
- * @param Traversable the data
- */
- protected function performDataBinding($data)
- {
- $this->reset();
-
- $keys=$this->getDataKeys();
- $keys->clear();
- $keyField=$this->getDataKeyField();
-
- $items=$this->getItems();
- $itemIndex=0;
- $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
- foreach($data as $key=>$dataItem)
- {
- if($keyField!=='')
- $keys->add($this->getDataFieldValue($dataItem,$keyField));
- else
- $keys->add($key);
- if($itemIndex===0)
- $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
- if($hasSeparator && $itemIndex>0)
- $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
- $itemType=$itemIndex%2==0?TListItemType::Item : TListItemType::AlternatingItem;
- $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
- $itemIndex++;
- }
- if($itemIndex>0)
- $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
- else
- {
- $this->createEmptyContent();
- $this->dataBindChildren();
- }
- $this->setViewState('ItemCount',$itemIndex,0);
- }
-
- /**
- * This method overrides parent's implementation to handle
- * {@link onItemCommand OnItemCommand} event which is bubbled from
- * repeater items and their child controls.
- * This method should only be used by control developers.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TRepeaterCommandEventParameter)
- {
- $this->onItemCommand($param);
- return true;
- }
- else
- return false;
- }
-
- /**
- * Raises <b>OnItemCreated</b> event.
- * This method is invoked after a repeater item is created and instantiated with
- * template, but before added to the page hierarchy.
- * The repeater item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TRepeaterItemEventParameter event parameter
- */
- public function onItemCreated($param)
- {
- $this->raiseEvent('OnItemCreated',$this,$param);
- }
-
- /**
- * Raises <b>OnItemDataBound</b> event.
- * This method is invoked right after an item is data bound.
- * The repeater item control responsible for the event
- * can be determined from the event parameter.
- * If you override this method, be sure to call parent's implementation
- * so that event handlers have chance to respond to the event.
- * @param TRepeaterItemEventParameter event parameter
- */
- public function onItemDataBound($param)
- {
- $this->raiseEvent('OnItemDataBound',$this,$param);
- }
-
- /**
- * Raises <b>OnItemCommand</b> event.
- * This method is invoked after a button control in
- * a template raises <b>OnCommand</b> event.
- * The repeater control responsible for the event
- * can be determined from the event parameter.
- * The event parameter also contains the information about
- * the initial sender of the <b>OnCommand</b> event, command name
- * and command parameter.
- * You may override this method to provide customized event handling.
- * Be sure to call parent's implementation so that
- * event handlers have chance to respond to the event.
- * @param TRepeaterCommandEventParameter event parameter
- */
- public function onItemCommand($param)
- {
- $this->raiseEvent('OnItemCommand',$this,$param);
- }
-
- /**
- * Returns the value of the data at the specified field.
- * If data is an array, TMap or TList, the value will be returned at the index
- * of the specified field. If the data is a component with a property named
- * as the field name, the property value will be returned.
- * Otherwise, an exception will be raised.
- * @param mixed data item
- * @param mixed field name
- * @return mixed data value at the specified field
- * @throws TInvalidDataValueException if the data is invalid
- */
- protected function getDataFieldValue($data,$field)
- {
- return TDataFieldAccessor::getDataFieldValue($data,$field);
- }
-}
-
-/**
- * TRepeaterItemEventParameter class
- *
- * TRepeaterItemEventParameter encapsulates the parameter data for
- * {@link TRepeater::onItemCreated ItemCreated} event of {@link TRepeater} controls.
- * The {@link getItem Item} property indicates the repeater item related with the event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItemEventParameter extends TEventParameter
-{
- /**
- * The repeater item control responsible for the event.
- * @var TControl
- */
- private $_item=null;
-
- /**
- * Constructor.
- * @param TControl repeater item related with the corresponding event
- */
- public function __construct($item)
- {
- $this->_item=$item;
- }
-
- /**
- * @return TControl repeater item related with the corresponding event
- */
- public function getItem()
- {
- return $this->_item;
- }
-}
-
-/**
- * TRepeaterCommandEventParameter class
- *
- * TRepeaterCommandEventParameter encapsulates the parameter data for
- * {@link TRepeater::onItemCommand ItemCommand} event of {@link TRepeater} controls.
- *
- * The {@link getItem Item} property indicates the repeater item related with the event.
- * The {@link getCommandSource CommandSource} refers to the control that originally
- * raises the Command event.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterCommandEventParameter extends TCommandEventParameter
-{
- /**
- * @var TControl the repeater item control responsible for the event.
- */
- private $_item=null;
- /**
- * @var TControl the control originally raises the <b>OnCommand</b> event.
- */
- private $_source=null;
-
- /**
- * Constructor.
- * @param TControl repeater item responsible for the event
- * @param TControl original event sender
- * @param TCommandEventParameter original event parameter
- */
- public function __construct($item,$source,TCommandEventParameter $param)
- {
- $this->_item=$item;
- $this->_source=$source;
- parent::__construct($param->getCommandName(),$param->getCommandParameter());
- }
-
- /**
- * @return TControl the repeater item control responsible for the event.
- */
- public function getItem()
- {
- return $this->_item;
- }
-
- /**
- * @return TControl the control originally raises the <b>OnCommand</b> event.
- */
- public function getCommandSource()
- {
- return $this->_source;
- }
-}
-
-/**
- * TRepeaterItem class
- *
- * A TRepeaterItem control represents an item in the {@link TRepeater} control,
- * such as heading section, footer section, or a data item.
- * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
- * and {@link getDataItem DataItem} properties, respectively. The type of the item
- * is given by {@link getItemType ItemType} property.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItem extends TControl implements INamingContainer, IItemDataRenderer
-{
- /**
- * index of the data item in the Items collection of repeater
- */
- private $_itemIndex;
- /**
- * type of the TRepeaterItem
- * @var TListItemType
- */
- private $_itemType;
- /**
- * data associated with this item
- * @var mixed
- */
- private $_data;
-
- /**
- * @return TListItemType item type
- */
- public function getItemType()
- {
- return $this->_itemType;
- }
-
- /**
- * @param TListItemType item type.
- */
- public function setItemType($value)
- {
- $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
- }
-
- /**
- * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
- * If the item is not in the collection (e.g. it is a header item), it returns -1.
- * @return integer zero-based index of the item.
- */
- public function getItemIndex()
- {
- return $this->_itemIndex;
- }
-
- /**
- * Sets the zero-based index for the item.
- * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
- * @param integer zero-based index of the item.
- */
- public function setItemIndex($value)
- {
- $this->_itemIndex=TPropertyValue::ensureInteger($value);
- }
-
- /**
- * @return mixed data associated with the item
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->_data;
- }
-
- /**
- * @param mixed data to be associated with the item
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->_data=$value;
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @return mixed data associated with the item
- * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
- */
- public function getDataItem()
- {
- return $this->getData();
- }
-
- /**
- * This property is deprecated since v3.1.0.
- * @param mixed data to be associated with the item
- * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
- */
- public function setDataItem($value)
- {
- return $this->setData($value);
- }
-
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
-
-/**
- * TRepeaterItemCollection class.
- *
- * TRepeaterItemCollection represents a collection of repeater items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRepeaterItemCollection extends TList
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by inserting only objects that are descendant of {@link TControl}.
- * @param integer the speicified position.
- * @param TControl new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a control.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TControl)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('repeateritemcollection_item_invalid');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TDataBoundControl and TDataFieldAccessor cass
+ */
+Prado::using('System.Web.UI.WebControls.TDataBoundControl');
+Prado::using('System.Util.TDataFieldAccessor');
+
+/**
+ * TRepeater class.
+ *
+ * TRepeater displays its content repeatedly based on the data fetched from
+ * {@link setDataSource DataSource}.
+ * The repeated contents in TRepeater are called items, which are controls and
+ * can be accessed through {@link getItems Items}. When {@link dataBind()} is invoked,
+ * TRepeater creates an item for each row of data and binds the data row to the item.
+ * Optionally, a repeater can have a header, a footer and/or separators between items.
+ *
+ * The layout of the repeated contents are specified by inline templates.
+ * Repeater items, header, footer, etc. are being instantiated with the corresponding
+ * templates when data is being bound to the repeater.
+ *
+ * Since v3.1.0, the layout can also be specified by renderers. A renderer is a control class
+ * that can be instantiated as repeater items, header, etc. A renderer can thus be viewed
+ * as an external template (in fact, it can also be non-templated controls).
+ *
+ * A renderer can be any control class.
+ * - If the class implements {@link IDataRenderer}, the <b>Data</b>
+ * property will be set as the data row during databinding. Many PRADO controls
+ * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
+ * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
+ * as the zero-based index of the item in the repeater item collection, and
+ * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
+ * {@link TRepeaterItemRenderer} may be used as the convenient base class which
+ * already implements {@link IDataItemRenderer}.
+ *
+ * The following properties are used to specify different types of template and renderer
+ * for a repeater:
+ * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
+ * for each repeated row of data
+ * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
+ * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
+ * will be used instead.
+ * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
+ * for the repeater header.
+ * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
+ * for the repeater footer.
+ * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
+ * for content to be displayed between items.
+ * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
+ * used when data bound to the repeater is empty.
+ *
+ * If a content type is defined with both a template and a renderer, the latter takes precedence.
+ *
+ * When {@link dataBind()} is being called, TRepeater undergoes the following lifecycles for each row of data:
+ * - create item based on templates or renderers
+ * - set the row of data to the item
+ * - raise {@link onItemCreated OnItemCreated}:
+ * - add the item as a child control
+ * - call dataBind() of the item
+ * - raise {@link onItemDataBound OnItemDataBound}:
+ *
+ * TRepeater raises an {@link onItemCommand OnItemCommand} whenever a button control
+ * within some repeater item raises a <b>OnCommand</b> event. Therefore,
+ * you can handle all sorts of <b>OnCommand</b> event in a central place by
+ * writing an event handler for {@link onItemCommand OnItemCommand}.
+ *
+ * When a page containing a repeater is post back, the repeater will restore automatically
+ * all its contents, including items, header, footer and separators.
+ * However, the data row associated with each item will not be recovered and become null.
+ * To access the data, use one of the following ways:
+ * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
+ * the specified repeater item and use the key to fetch the corresponding data
+ * from some persistent storage such as DB.
+ * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
+ * Be aware though, if the size of your dataset is big, your page size will become big. Some
+ * complex data may also have serializing problem if saved in viewstate.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeater extends TDataBoundControl implements INamingContainer
+{
+ /**
+ * Repeater item types
+ * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
+ */
+ const IT_HEADER='Header';
+ const IT_FOOTER='Footer';
+ const IT_ITEM='Item';
+ const IT_SEPARATOR='Separator';
+ const IT_ALTERNATINGITEM='AlternatingItem';
+
+ /**
+ * @var ITemplate template for repeater items
+ */
+ private $_itemTemplate=null;
+ /**
+ * @var ITemplate template for each alternating item
+ */
+ private $_alternatingItemTemplate=null;
+ /**
+ * @var ITemplate template for header
+ */
+ private $_headerTemplate=null;
+ /**
+ * @var ITemplate template for footer
+ */
+ private $_footerTemplate=null;
+ /**
+ * @var ITemplate template used for repeater when no data is bound
+ */
+ private $_emptyTemplate=null;
+ /**
+ * @var ITemplate template for separator
+ */
+ private $_separatorTemplate=null;
+ /**
+ * @var TRepeaterItemCollection list of repeater items
+ */
+ private $_items=null;
+ /**
+ * @var TControl header item
+ */
+ private $_header=null;
+ /**
+ * @var TControl footer item
+ */
+ private $_footer=null;
+
+
+ /**
+ * @return string the class name for repeater items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater items.
+ * This property takes precedence over {@link getItemTemplate ItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setItemTemplate
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for alternative repeater items. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getAlternatingItemRenderer()
+ {
+ return $this->getViewState('AlternatingItemRenderer','');
+ }
+
+ /**
+ * Sets the alternative item renderer class.
+ *
+ * If not empty, the class will be used to instantiate as alternative repeater items.
+ * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setAlternatingItemTemplate
+ * @since 3.1.0
+ */
+ public function setAlternatingItemRenderer($value)
+ {
+ $this->setViewState('AlternatingItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater item separators. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getSeparatorRenderer()
+ {
+ return $this->getViewState('SeparatorRenderer','');
+ }
+
+ /**
+ * Sets the repeater item separator renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater item separators.
+ * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setSeparatorTemplate
+ * @since 3.1.0
+ */
+ public function setSeparatorRenderer($value)
+ {
+ $this->setViewState('SeparatorRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater header item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getHeaderRenderer()
+ {
+ return $this->getViewState('HeaderRenderer','');
+ }
+
+ /**
+ * Sets the repeater header renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater header item.
+ * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setHeaderTemplate
+ * @since 3.1.0
+ */
+ public function setHeaderRenderer($value)
+ {
+ $this->setViewState('HeaderRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for repeater footer item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getFooterRenderer()
+ {
+ return $this->getViewState('FooterRenderer','');
+ }
+
+ /**
+ * Sets the repeater footer renderer class.
+ *
+ * If not empty, the class will be used to instantiate as repeater footer item.
+ * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setFooterTemplate
+ * @since 3.1.0
+ */
+ public function setFooterRenderer($value)
+ {
+ $this->setViewState('FooterRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for empty repeater item. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEmptyRenderer()
+ {
+ return $this->getViewState('EmptyRenderer','');
+ }
+
+ /**
+ * Sets the repeater empty renderer class.
+ *
+ * The empty renderer is created as the child of the repeater
+ * if data bound to the repeater is empty.
+ * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
+ *
+ * @param string the renderer class name in namespace format.
+ * @see setEmptyTemplate
+ * @since 3.1.0
+ */
+ public function setEmptyRenderer($value)
+ {
+ $this->setViewState('EmptyRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the template for repeater items
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for repeater items
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the alternative template string for the item
+ */
+ public function getAlternatingItemTemplate()
+ {
+ return $this->_alternatingItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the alternative item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setAlternatingItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_alternatingItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','AlternatingItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','FooterTemplate');
+ }
+
+ /**
+ * @return ITemplate the template applied when no data is bound to the repeater
+ */
+ public function getEmptyTemplate()
+ {
+ return $this->_emptyTemplate;
+ }
+
+ /**
+ * @param ITemplate the template applied when no data is bound to the repeater
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEmptyTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_emptyTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','EmptyTemplate');
+ }
+
+ /**
+ * @return ITemplate the separator template
+ */
+ public function getSeparatorTemplate()
+ {
+ return $this->_separatorTemplate;
+ }
+
+ /**
+ * @param ITemplate the separator template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setSeparatorTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_separatorTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('repeater_template_required','SeparatorTemplate');
+ }
+
+ /**
+ * @return TControl the header item
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TControl the footer item
+ */
+ public function getFooter()
+ {
+ return $this->_footer;
+ }
+
+ /**
+ * @return TRepeaterItemCollection list of repeater item controls
+ */
+ public function getItems()
+ {
+ if(!$this->_items)
+ $this->_items=new TRepeaterItemCollection;
+ return $this->_items;
+ }
+
+ /**
+ * @return string the field of the data source that provides the keys of the list items.
+ */
+ public function getDataKeyField()
+ {
+ return $this->getViewState('DataKeyField','');
+ }
+
+ /**
+ * @param string the field of the data source that provides the keys of the list items.
+ */
+ public function setDataKeyField($value)
+ {
+ $this->setViewState('DataKeyField',$value,'');
+ }
+
+ /**
+ * @return TList the keys used in the data listing control.
+ */
+ public function getDataKeys()
+ {
+ if(($dataKeys=$this->getViewState('DataKeys',null))===null)
+ {
+ $dataKeys=new TList;
+ $this->setViewState('DataKeys',$dataKeys,null);
+ }
+ return $dataKeys;
+ }
+
+ /**
+ * Creates a repeater item.
+ * This method invokes {@link createItem} to create a new repeater item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemInternal($itemIndex,$itemType)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TRepeaterItemEventParameter($item);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a repeater item and performs databinding.
+ * This method invokes {@link createItem} to create a new repeater item.
+ * @param integer zero-based item index.
+ * @param TListItemType item type
+ * @param mixed data to be associated with the item
+ * @return TControl the created item, null if item is not created
+ */
+ private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
+ {
+ if(($item=$this->createItem($itemIndex,$itemType))!==null)
+ {
+ $param=new TRepeaterItemEventParameter($item);
+ if($item instanceof IDataRenderer)
+ $item->setData($dataItem);
+ $this->onItemCreated($param);
+ $this->getControls()->add($item);
+ $item->dataBind();
+ $this->onItemDataBound($param);
+ return $item;
+ }
+ else
+ return null;
+ }
+
+ /**
+ * Creates a repeater item instance based on the item type and index.
+ * @param integer zero-based item index
+ * @param TListItemType item type
+ * @return TControl created repeater item
+ */
+ protected function createItem($itemIndex,$itemType)
+ {
+ $template=null;
+ $classPath=null;
+ switch($itemType)
+ {
+ case TListItemType::Item :
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ break;
+ case TListItemType::AlternatingItem :
+ if(($classPath=$this->getAlternatingItemRenderer())==='' && ($template=$this->_alternatingItemTemplate)===null)
+ {
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ }
+ break;
+ case TListItemType::Header :
+ $classPath=$this->getHeaderRenderer();
+ $template=$this->_headerTemplate;
+ break;
+ case TListItemType::Footer :
+ $classPath=$this->getFooterRenderer();
+ $template=$this->_footerTemplate;
+ break;
+ case TListItemType::Separator :
+ $classPath=$this->getSeparatorRenderer();
+ $template=$this->_separatorTemplate;
+ break;
+ default:
+ throw new TInvalidDataValueException('repeater_itemtype_unknown',$itemType);
+ }
+ if($classPath!=='')
+ {
+ $item=Prado::createComponent($classPath);
+ if($item instanceof IItemDataRenderer)
+ {
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ }
+ }
+ else if($template!==null)
+ {
+ $item=new TRepeaterItem;
+ $item->setItemIndex($itemIndex);
+ $item->setItemType($itemType);
+ $template->instantiateIn($item);
+ }
+ else
+ $item=null;
+
+ return $item;
+ }
+
+ /**
+ * Creates empty repeater content.
+ */
+ protected function createEmptyContent()
+ {
+ if(($classPath=$this->getEmptyRenderer())!=='')
+ $this->getControls()->add(Prado::createComponent($classPath));
+ else if($this->_emptyTemplate!==null)
+ $this->_emptyTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Renders the repeater.
+ * This method overrides the parent implementation by rendering the body
+ * content as the whole presentation of the repeater. Outer tag is not rendered.
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ if($this->_items && $this->_items->getCount() || $this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
+ $this->renderContents($writer);
+ }
+
+ /**
+ * Saves item count in viewstate.
+ * This method is invoked right before control state is to be saved.
+ */
+ public function saveState()
+ {
+ parent::saveState();
+ if($this->_items)
+ $this->setViewState('ItemCount',$this->_items->getCount(),0);
+ else
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Loads item count information from viewstate.
+ * This method is invoked right after control state is loaded.
+ */
+ public function loadState()
+ {
+ parent::loadState();
+ if(!$this->getIsDataBound())
+ $this->restoreItemsFromViewState();
+ $this->clearViewState('ItemCount');
+ }
+
+ /**
+ * Clears up all items in the repeater.
+ */
+ public function reset()
+ {
+ $this->getControls()->clear();
+ $this->getItems()->clear();
+ $this->_header=null;
+ $this->_footer=null;
+ }
+
+ /**
+ * Creates repeater items based on viewstate information.
+ */
+ protected function restoreItemsFromViewState()
+ {
+ $this->reset();
+ if(($itemCount=$this->getViewState('ItemCount',0))>0)
+ {
+ $items=$this->getItems();
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ $this->_header=$this->createItemInternal(-1,TListItemType::Header);
+ for($i=0;$i<$itemCount;++$i)
+ {
+ if($hasSeparator && $i>0)
+ $this->createItemInternal($i-1,TListItemType::Separator);
+ $itemType=$i%2==0?TListItemType::Item : TListItemType::AlternatingItem;
+ $items->add($this->createItemInternal($i,$itemType,false,null));
+ }
+ $this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
+ }
+ else
+ $this->createEmptyContent();
+ $this->clearChildState();
+ }
+
+ /**
+ * Performs databinding to populate repeater items from data source.
+ * This method is invoked by dataBind().
+ * You may override this function to provide your own way of data population.
+ * @param Traversable the data
+ */
+ protected function performDataBinding($data)
+ {
+ $this->reset();
+
+ $keys=$this->getDataKeys();
+ $keys->clear();
+ $keyField=$this->getDataKeyField();
+
+ $items=$this->getItems();
+ $itemIndex=0;
+ $hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
+ foreach($data as $key=>$dataItem)
+ {
+ if($keyField!=='')
+ $keys->add($this->getDataFieldValue($dataItem,$keyField));
+ else
+ $keys->add($key);
+ if($itemIndex===0)
+ $this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
+ if($hasSeparator && $itemIndex>0)
+ $this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
+ $itemType=$itemIndex%2==0?TListItemType::Item : TListItemType::AlternatingItem;
+ $items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
+ $itemIndex++;
+ }
+ if($itemIndex>0)
+ $this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
+ else
+ {
+ $this->createEmptyContent();
+ $this->dataBindChildren();
+ }
+ $this->setViewState('ItemCount',$itemIndex,0);
+ }
+
+ /**
+ * This method overrides parent's implementation to handle
+ * {@link onItemCommand OnItemCommand} event which is bubbled from
+ * repeater items and their child controls.
+ * This method should only be used by control developers.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TRepeaterCommandEventParameter)
+ {
+ $this->onItemCommand($param);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Raises <b>OnItemCreated</b> event.
+ * This method is invoked after a repeater item is created and instantiated with
+ * template, but before added to the page hierarchy.
+ * The repeater item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TRepeaterItemEventParameter event parameter
+ */
+ public function onItemCreated($param)
+ {
+ $this->raiseEvent('OnItemCreated',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemDataBound</b> event.
+ * This method is invoked right after an item is data bound.
+ * The repeater item control responsible for the event
+ * can be determined from the event parameter.
+ * If you override this method, be sure to call parent's implementation
+ * so that event handlers have chance to respond to the event.
+ * @param TRepeaterItemEventParameter event parameter
+ */
+ public function onItemDataBound($param)
+ {
+ $this->raiseEvent('OnItemDataBound',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnItemCommand</b> event.
+ * This method is invoked after a button control in
+ * a template raises <b>OnCommand</b> event.
+ * The repeater control responsible for the event
+ * can be determined from the event parameter.
+ * The event parameter also contains the information about
+ * the initial sender of the <b>OnCommand</b> event, command name
+ * and command parameter.
+ * You may override this method to provide customized event handling.
+ * Be sure to call parent's implementation so that
+ * event handlers have chance to respond to the event.
+ * @param TRepeaterCommandEventParameter event parameter
+ */
+ public function onItemCommand($param)
+ {
+ $this->raiseEvent('OnItemCommand',$this,$param);
+ }
+
+ /**
+ * Returns the value of the data at the specified field.
+ * If data is an array, TMap or TList, the value will be returned at the index
+ * of the specified field. If the data is a component with a property named
+ * as the field name, the property value will be returned.
+ * Otherwise, an exception will be raised.
+ * @param mixed data item
+ * @param mixed field name
+ * @return mixed data value at the specified field
+ * @throws TInvalidDataValueException if the data is invalid
+ */
+ protected function getDataFieldValue($data,$field)
+ {
+ return TDataFieldAccessor::getDataFieldValue($data,$field);
+ }
+}
+
+/**
+ * TRepeaterItemEventParameter class
+ *
+ * TRepeaterItemEventParameter encapsulates the parameter data for
+ * {@link TRepeater::onItemCreated ItemCreated} event of {@link TRepeater} controls.
+ * The {@link getItem Item} property indicates the repeater item related with the event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItemEventParameter extends TEventParameter
+{
+ /**
+ * The repeater item control responsible for the event.
+ * @var TControl
+ */
+ private $_item=null;
+
+ /**
+ * Constructor.
+ * @param TControl repeater item related with the corresponding event
+ */
+ public function __construct($item)
+ {
+ $this->_item=$item;
+ }
+
+ /**
+ * @return TControl repeater item related with the corresponding event
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+}
+
+/**
+ * TRepeaterCommandEventParameter class
+ *
+ * TRepeaterCommandEventParameter encapsulates the parameter data for
+ * {@link TRepeater::onItemCommand ItemCommand} event of {@link TRepeater} controls.
+ *
+ * The {@link getItem Item} property indicates the repeater item related with the event.
+ * The {@link getCommandSource CommandSource} refers to the control that originally
+ * raises the Command event.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterCommandEventParameter extends TCommandEventParameter
+{
+ /**
+ * @var TControl the repeater item control responsible for the event.
+ */
+ private $_item=null;
+ /**
+ * @var TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ private $_source=null;
+
+ /**
+ * Constructor.
+ * @param TControl repeater item responsible for the event
+ * @param TControl original event sender
+ * @param TCommandEventParameter original event parameter
+ */
+ public function __construct($item,$source,TCommandEventParameter $param)
+ {
+ $this->_item=$item;
+ $this->_source=$source;
+ parent::__construct($param->getCommandName(),$param->getCommandParameter());
+ }
+
+ /**
+ * @return TControl the repeater item control responsible for the event.
+ */
+ public function getItem()
+ {
+ return $this->_item;
+ }
+
+ /**
+ * @return TControl the control originally raises the <b>OnCommand</b> event.
+ */
+ public function getCommandSource()
+ {
+ return $this->_source;
+ }
+}
+
+/**
+ * TRepeaterItem class
+ *
+ * A TRepeaterItem control represents an item in the {@link TRepeater} control,
+ * such as heading section, footer section, or a data item.
+ * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
+ * and {@link getDataItem DataItem} properties, respectively. The type of the item
+ * is given by {@link getItemType ItemType} property.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItem extends TControl implements INamingContainer, IItemDataRenderer
+{
+ /**
+ * index of the data item in the Items collection of repeater
+ */
+ private $_itemIndex;
+ /**
+ * type of the TRepeaterItem
+ * @var TListItemType
+ */
+ private $_itemType;
+ /**
+ * data associated with this item
+ * @var mixed
+ */
+ private $_data;
+
+ /**
+ * @return TListItemType item type
+ */
+ public function getItemType()
+ {
+ return $this->_itemType;
+ }
+
+ /**
+ * @param TListItemType item type.
+ */
+ public function setItemType($value)
+ {
+ $this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
+ }
+
+ /**
+ * Returns a value indicating the zero-based index of the item in the corresponding data control's item collection.
+ * If the item is not in the collection (e.g. it is a header item), it returns -1.
+ * @return integer zero-based index of the item.
+ */
+ public function getItemIndex()
+ {
+ return $this->_itemIndex;
+ }
+
+ /**
+ * Sets the zero-based index for the item.
+ * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
+ * @param integer zero-based index of the item.
+ */
+ public function setItemIndex($value)
+ {
+ $this->_itemIndex=TPropertyValue::ensureInteger($value);
+ }
+
+ /**
+ * @return mixed data associated with the item
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->_data;
+ }
+
+ /**
+ * @param mixed data to be associated with the item
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->_data=$value;
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @return mixed data associated with the item
+ * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
+ */
+ public function getDataItem()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * This property is deprecated since v3.1.0.
+ * @param mixed data to be associated with the item
+ * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
+ */
+ public function setDataItem($value)
+ {
+ return $this->setData($value);
+ }
+
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+
+/**
+ * TRepeaterItemCollection class.
+ *
+ * TRepeaterItemCollection represents a collection of repeater items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRepeaterItemCollection extends TList
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by inserting only objects that are descendant of {@link TControl}.
+ * @param integer the speicified position.
+ * @param TControl new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a control.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TControl)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('repeateritemcollection_item_invalid');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TRepeaterItemRenderer.php b/framework/Web/UI/WebControls/TRepeaterItemRenderer.php
index 85991b38..fe5171ad 100644
--- a/framework/Web/UI/WebControls/TRepeaterItemRenderer.php
+++ b/framework/Web/UI/WebControls/TRepeaterItemRenderer.php
@@ -1,50 +1,50 @@
-<?php
-/**
- * TRepeaterItemRenderer class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TRepeaterItemRenderer class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TRepeater');
-Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
-
-/**
- * TRepeaterItemRenderer class
- *
- * TRepeaterItemRenderer can be used as a convenient base class to
- * define an item renderer class specific for {@link TRepeater}.
- *
- * TRepeaterItemRenderer extends {@link TItemDataRenderer} and implements
- * the bubbling scheme for the OnCommand event of repeater items.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.0
- */
-class TRepeaterItemRenderer extends TItemDataRenderer
-{
- /**
- * This method overrides parent's implementation by wrapping event parameter
- * for <b>OnCommand</b> event with item information.
- * @param TControl the sender of the event
- * @param TEventParameter event parameter
- * @return boolean whether the event bubbling should stop here.
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
- return true;
- }
- else
- return false;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TRepeater');
+Prado::using('System.Web.UI.WebControls.TItemDataRenderer');
+
+/**
+ * TRepeaterItemRenderer class
+ *
+ * TRepeaterItemRenderer can be used as a convenient base class to
+ * define an item renderer class specific for {@link TRepeater}.
+ *
+ * TRepeaterItemRenderer extends {@link TItemDataRenderer} and implements
+ * the bubbling scheme for the OnCommand event of repeater items.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.0
+ */
+class TRepeaterItemRenderer extends TItemDataRenderer
+{
+ /**
+ * This method overrides parent's implementation by wrapping event parameter
+ * for <b>OnCommand</b> event with item information.
+ * @param TControl the sender of the event
+ * @param TEventParameter event parameter
+ * @return boolean whether the event bubbling should stop here.
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $this->raiseBubbleEvent($this,new TRepeaterCommandEventParameter($this,$sender,$param));
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TRequiredFieldValidator.php b/framework/Web/UI/WebControls/TRequiredFieldValidator.php
index 97555b82..89b142bf 100644
--- a/framework/Web/UI/WebControls/TRequiredFieldValidator.php
+++ b/framework/Web/UI/WebControls/TRequiredFieldValidator.php
@@ -1,138 +1,138 @@
-<?php
-/**
- * TRequiredFieldValidator class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TRequiredFieldValidator class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Using TBaseValidator class
- */
-Prado::using('System.Web.UI.WebControls.TBaseValidator');
-
-/**
- * TRequiredFieldValidator class
- *
- * TRequiredFieldValidator makes the associated input control a required field.
- * The input control fails validation if its value does not change from
- * the {@link setInitialValue InitialValue} property upon losing focus.
- *
- * Validation will also succeed if input is of TListControl type and the number
- * of selected values different from the initial value is greater than zero.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TRequiredFieldValidator extends TBaseValidator
-{
- /**
- * Gets the name of the javascript class responsible for performing validation for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TRequiredFieldValidator';
- }
-
- /**
- * @return string the initial value of the associated input control. Defaults to empty string.
- * If the associated input control does not change from this initial value
- * upon postback, the validation fails.
- */
- public function getInitialValue()
- {
- return $this->getViewState('InitialValue','');
- }
-
- /**
- * @param string the initial value of the associated input control.
- * If the associated input control does not change from this initial value
- * upon postback, the validation fails.
- */
- public function setInitialValue($value)
- {
- $this->setViewState('InitialValue',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * This method overrides the parent's implementation.
- * The validation succeeds if the input component changes its data
- * from the {@link getInitialValue InitialValue} or the input control is not given.
- *
- * Validation will also succeed if input is of TListControl type and the
- * number of selected values different from the initial value is greater
- * than zero.
- *
- * @return boolean whether the validation succeeds
- */
- protected function evaluateIsValid()
- {
- $control = $this->getValidationTarget();
- if($control instanceof TListControl)
- return $this->validateListControl($control);
- else if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
- return $this->validateRadioButtonGroup($control);
- else
- return $this->validateStandardControl($control);
- }
-
- private function validateListControl($control)
- {
- $initial = trim($this->getInitialValue());
- $count = 0;
- foreach($control->getItems() as $item)
- {
- if($item->getSelected() && $item->getValue() != $initial)
- $count++;
- }
- return $count > 0;
- }
-
- private function validateRadioButtonGroup($control)
- {
- $initial = trim($this->getInitialValue());
- foreach($control->getRadioButtonsInGroup() as $radio)
- {
- if($radio->getChecked())
- {
- if(strlen($value = $radio->getValue()) > 0)
- return $value !== $initial;
- else
- return true;
- }
- }
- return false;
- }
-
- private function validateStandardControl($control)
- {
- $initial = trim($this->getInitialValue());
- $value=$this->getValidationValue($control);
- return (is_bool($value) && $value) || trim($value)!==$initial;
- }
-
- /**
- * Returns an array of javascript validator options.
- * @return array javascript validator options.
- */
- protected function getClientScriptOptions()
- {
- $options = parent::getClientScriptOptions();
- $options['InitialValue']=$this->getInitialValue();
- $control = $this->getValidationTarget();
- if($control instanceof TListControl)
- $options['TotalItems'] = $control->getItemCount();
- if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
- $options['GroupName'] = $control->getGroupName();
- return $options;
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Using TBaseValidator class
+ */
+Prado::using('System.Web.UI.WebControls.TBaseValidator');
+
+/**
+ * TRequiredFieldValidator class
+ *
+ * TRequiredFieldValidator makes the associated input control a required field.
+ * The input control fails validation if its value does not change from
+ * the {@link setInitialValue InitialValue} property upon losing focus.
+ *
+ * Validation will also succeed if input is of TListControl type and the number
+ * of selected values different from the initial value is greater than zero.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TRequiredFieldValidator extends TBaseValidator
+{
+ /**
+ * Gets the name of the javascript class responsible for performing validation for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TRequiredFieldValidator';
+ }
+
+ /**
+ * @return string the initial value of the associated input control. Defaults to empty string.
+ * If the associated input control does not change from this initial value
+ * upon postback, the validation fails.
+ */
+ public function getInitialValue()
+ {
+ return $this->getViewState('InitialValue','');
+ }
+
+ /**
+ * @param string the initial value of the associated input control.
+ * If the associated input control does not change from this initial value
+ * upon postback, the validation fails.
+ */
+ public function setInitialValue($value)
+ {
+ $this->setViewState('InitialValue',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * This method overrides the parent's implementation.
+ * The validation succeeds if the input component changes its data
+ * from the {@link getInitialValue InitialValue} or the input control is not given.
+ *
+ * Validation will also succeed if input is of TListControl type and the
+ * number of selected values different from the initial value is greater
+ * than zero.
+ *
+ * @return boolean whether the validation succeeds
+ */
+ protected function evaluateIsValid()
+ {
+ $control = $this->getValidationTarget();
+ if($control instanceof TListControl)
+ return $this->validateListControl($control);
+ else if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
+ return $this->validateRadioButtonGroup($control);
+ else
+ return $this->validateStandardControl($control);
+ }
+
+ private function validateListControl($control)
+ {
+ $initial = trim($this->getInitialValue());
+ $count = 0;
+ foreach($control->getItems() as $item)
+ {
+ if($item->getSelected() && $item->getValue() != $initial)
+ $count++;
+ }
+ return $count > 0;
+ }
+
+ private function validateRadioButtonGroup($control)
+ {
+ $initial = trim($this->getInitialValue());
+ foreach($control->getRadioButtonsInGroup() as $radio)
+ {
+ if($radio->getChecked())
+ {
+ if(strlen($value = $radio->getValue()) > 0)
+ return $value !== $initial;
+ else
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private function validateStandardControl($control)
+ {
+ $initial = trim($this->getInitialValue());
+ $value=$this->getValidationValue($control);
+ return (is_bool($value) && $value) || trim($value)!==$initial;
+ }
+
+ /**
+ * Returns an array of javascript validator options.
+ * @return array javascript validator options.
+ */
+ protected function getClientScriptOptions()
+ {
+ $options = parent::getClientScriptOptions();
+ $options['InitialValue']=$this->getInitialValue();
+ $control = $this->getValidationTarget();
+ if($control instanceof TListControl)
+ $options['TotalItems'] = $control->getItemCount();
+ if($control instanceof TRadioButton && strlen($control->getGroupName()) > 0)
+ $options['GroupName'] = $control->getGroupName();
+ return $options;
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TSafeHtml.php b/framework/Web/UI/WebControls/TSafeHtml.php
index e88277d4..1cd0a597 100644
--- a/framework/Web/UI/WebControls/TSafeHtml.php
+++ b/framework/Web/UI/WebControls/TSafeHtml.php
@@ -1,85 +1,85 @@
-<?php
-/**
- * TSafeHtml class file
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TSafeHtml class
- *
- * TSafeHtml is a control that strips down all potentially dangerous
- * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML}
- * project. According to the SafeHTML project, it tries to safeguard
- * the following situations when the string is to be displayed to end-users,
- * - Opening tag without its closing tag
- * - closing tag without its opening tag
- * - any of these tags: base, basefont, head, html, body, applet, object,
- * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link,
- * meta, style, title, blink, xml, etc.
- * - any of these attributes: on*, data*, dynsrc
- * - javascript:/vbscript:/about: etc. protocols
- * - expression/behavior etc. in styles
- * - any other active content.
- *
- * To use TSafeHtml, simply enclose the content to be secured within
- * the body of TSafeHtml in a template.
- *
- * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property
- * to ensure the contents gets parsed correctly.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TSafeHtml extends TControl
-{
- /**
- * Sets whether to parse the contents as UTF-7. This property enables a routine
- * that repacks the content as UTF-7 before parsing it. Defaults to false.
- * @param boolean whether to parse the contents as UTF-7
- */
- public function setRepackUTF7($value)
- {
- $this->setViewState('RepackUTF7',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether to parse the contents as UTF-7. Defaults to false.
- */
- public function getRepackUTF7()
- {
- return $this->getViewState('RepackUTF7',false);
- }
-
- /**
- * Renders body content.
- * This method overrides parent implementation by removing
- * malicious javascript code from the body content
- * @param THtmlWriter writer
- */
- public function render($writer)
- {
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
- parent::render($htmlWriter);
- $writer->write($this->parseSafeHtml($htmlWriter->flush()));
- }
-
- /**
- * Use SafeHTML to remove malicous javascript from the HTML content.
- * @param string HTML content
- * @return string safer HTML content
- */
- protected function parseSafeHtml($text)
- {
- $renderer = Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
- return $renderer->parse($text, $this->getRepackUTF7());
- }
-}
-
+<?php
+/**
+ * TSafeHtml class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TSafeHtml class
+ *
+ * TSafeHtml is a control that strips down all potentially dangerous
+ * HTML content. It is mainly a wrapper of {@link http://pear.php.net/package/SafeHTML SafeHTML}
+ * project. According to the SafeHTML project, it tries to safeguard
+ * the following situations when the string is to be displayed to end-users,
+ * - Opening tag without its closing tag
+ * - closing tag without its opening tag
+ * - any of these tags: base, basefont, head, html, body, applet, object,
+ * iframe, frame, frameset, script, layer, ilayer, embed, bgsound, link,
+ * meta, style, title, blink, xml, etc.
+ * - any of these attributes: on*, data*, dynsrc
+ * - javascript:/vbscript:/about: etc. protocols
+ * - expression/behavior etc. in styles
+ * - any other active content.
+ *
+ * To use TSafeHtml, simply enclose the content to be secured within
+ * the body of TSafeHtml in a template.
+ *
+ * If the content is encoded in UTF-7, you'll need to enable the {@link setRepackUTF7 RepackUTF7} property
+ * to ensure the contents gets parsed correctly.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TSafeHtml extends TControl
+{
+ /**
+ * Sets whether to parse the contents as UTF-7. This property enables a routine
+ * that repacks the content as UTF-7 before parsing it. Defaults to false.
+ * @param boolean whether to parse the contents as UTF-7
+ */
+ public function setRepackUTF7($value)
+ {
+ $this->setViewState('RepackUTF7',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether to parse the contents as UTF-7. Defaults to false.
+ */
+ public function getRepackUTF7()
+ {
+ return $this->getViewState('RepackUTF7',false);
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides parent implementation by removing
+ * malicious javascript code from the body content
+ * @param THtmlWriter writer
+ */
+ public function render($writer)
+ {
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
+ parent::render($htmlWriter);
+ $writer->write($this->parseSafeHtml($htmlWriter->flush()));
+ }
+
+ /**
+ * Use SafeHTML to remove malicous javascript from the HTML content.
+ * @param string HTML content
+ * @return string safer HTML content
+ */
+ protected function parseSafeHtml($text)
+ {
+ $renderer = Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
+ return $renderer->parse($text, $this->getRepackUTF7());
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TSlider.php b/framework/Web/UI/WebControls/TSlider.php
index ce080f5f..06df52b6 100644
--- a/framework/Web/UI/WebControls/TSlider.php
+++ b/framework/Web/UI/WebControls/TSlider.php
@@ -1,574 +1,574 @@
-<?php
-/**
- * TSlider class file.
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-
-/**
- * TSlider class
- *
- * TSlider displays a slider for numeric input purpose. A slider consists of a 'track',
- * which define the range of possible value, and a 'handle' which can slide on the track, to select
- * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction}
- * property. By default, it's horizontal.
- *
- * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties.
- * The default range is from 0 to 100.
- * The {@link SetStepSize StepSize} property can be used to define the <b>step</b> between 2 values inside the range.
- * Notice that this step will be recomputed if there is more than 200 values between the range boundaries.
- * You can also provide the allowed values by setting the {@link SetValues Values} array.
- *
- * A 'Progress Indicator' can be displayed within the track with the {@link SetProgressIndicator ProgressIndicator} property.
- *
- * The TSlider control can be easily customized using CssClasses. You can provide your own css file, using the
- * {@link SetCssUrl CssUrl} property.
- * The css class for TSlider can be set by the {@link setCssClass CssClass} property. Default value is "Slider HorizontalSlider"
- * for an horizontal slider, and "Slider VerticalSlider" for a vertical one.
- *
- * If {@link SetAutoPostBack AutoPostBack} property is true, postback is sent as soon as the value changed.
- *
- * TSlider raises the {@link onValueChanged} event when the value of the slider has changed during postback.
- *
- * You can also attach ClientSide javascript events handler to the slider :
- * - ClientSide.onSlide is called when the handle is slided on the track. You can get the current value in the <b>value</b>
- * javascript variable. You can use this event to update on client side a label with the current value
- * - ClientSide.onChange is called when the slider value has changed (at the end of a move).
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSlider extends TWebControl implements IPostBackDataHandler, IDataRenderer
-{
- const MAX_STEPS=200;
- /**
- * @var TSliderHandle handle component
- */
- private $_handle;
- /*
- * @var boolean Wether the data has changed during postback
- */
- private $_dataChanged=false;
- /**
- * @var TSliderClientScript Clients side javascripts
- */
- private $_clientScript=null;
-
- /**
- * @return TSliderDirection Direction of slider (Horizontal or Vertical). Defaults to Horizontal.
- */
- public function getDirection()
- {
- return $this->getViewState('Direction', TSliderDirection::Horizontal);
- }
-
- /**
- * @param TSliderDirection Direction of slider (Horizontal or Vertical)
- */
- public function setDirection($value)
- {
- $this->setViewState('Direction', TPropertyValue::ensureEnum($value,'TSliderDirection'),TSliderDirection::Horizontal);
- }
-
- /**
- * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to '' (a default CSS file will be applied in this case.)
- */
- public function getCssUrl()
- {
- return $this->getViewState('CssUrl','');
- }
-
- /**
- * @param string URL for the CSS file including all relevant CSS class definitions.
- */
- public function setCssUrl($value)
- {
- $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return float Maximum value for the slider. Defaults to 100.0.
- */
- public function getMaxValue()
- {
- return $this->getViewState('MaxValue',100.0);
- }
-
- /**
- * @param float Maximum value for slider
- */
- public function setMaxValue($value)
- {
- $this->setViewState('MaxValue', TPropertyValue::ensureFloat($value),100.0);
- }
-
- /**
- * @return float Minimum value for slider. Defaults to 0.0.
- */
- public function getMinValue()
- {
- return $this->getViewState('MinValue',0.0);
- }
-
- /**
- * @param float Minimum value for slider
- */
- public function setMinValue($value)
- {
- $this->setViewState('MinValue', TPropertyValue::ensureFloat($value),0.0);
- }
-
- /**
- * @return float Step size. Defaults to 1.0.
- */
- public function getStepSize()
- {
- return $this->getViewState('StepSize', 1.0);
- }
-
- /**
- * Sets the step size used to determine the places where the slider handle can stop at.
- * An evenly distributed stop marks will be generated according to
- * {@link getMinValue MinValue}, {@link getMaxValue MaxValue} and StepSize.
- * To use uneven stop marks, set {@link setValues Values}.
- * @param float Step size.
- */
- public function setStepSize($value)
- {
- $this->setViewState('StepSize', $value, 1.0);
- }
-
- /**
- * @return boolean wether to display a progress indicator or not. Defaults to true.
- */
- public function getProgressIndicator ()
- {
- return $this->getViewState('ProgressIndicator', true);
- }
-
- /**
- * @param boolean wether to display a progress indicator or not. Defaults to true.
- */
- public function setProgressIndicator ($value)
- {
- $this->setViewState('ProgressIndicator', TPropertyValue::ensureBoolean($value), true);
- }
- /**
- * @return float current value of slider
- */
- public function getValue()
- {
- return $this->getViewState('Value',0.0);
- }
-
- /**
- * @param float current value of slider
- */
- public function setValue($value)
- {
- $this->setViewState('Value', TPropertyValue::ensureFloat($value),0.0);
- }
-
- /**
- * Returns the value of the TSlider control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getValue()}.
- * @return string the value of the TSlider control.
- * @see getValue
- */
- public function getData()
- {
- return $this->getValue();
- }
-
- /**
- * Sets the value of the TSlider control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setValue()}.
- * @param string the value of the TSlider control.
- * @see setValue
- */
- public function setData($value)
- {
- $this->setValue($value);
- }
-
- /**
- * @return array list of allowed values the slider can take. Defaults to an empty array.
- */
- public function getValues()
- {
- return $this->getViewState('Values', array());
- }
-
- /**
- * Sets the possible values that the slider can take.
- * If this is set, {@link setStepSize StepSize} will be ignored. The latter
- * generates a set of evenly distributed candidate values.
- * @param array list of allowed values the slider can take
- */
- public function setValues($value)
- {
- $this->setViewState('Values', TPropertyValue::ensureArray($value), array());
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user modifies the slider value. Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * modifies the slider value.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TSlider';
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getValue Value} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- $this->onValueChanged(null);
- }
-
- /**
- * Raises <b>OnValueChanged</b> event.
- * This method is invoked when the {@link getValue Value}
- * property changes on postback.
- * If you override this method, be sure to call the parent implementation to ensure
- * the invocation of the attached event handlers.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onValueChanged($param)
- {
- $this->raiseEvent('OnValueChanged',$this,$param);
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=(float)$values[$this->getClientID().'_1'];
- if($this->getValue()!==$value)
- {
- $this->setValue($value);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Gets the TSliderClientScript to set the TSlider event handlers.
- *
- * The slider on the client-side supports the following events.
- * # <tt>OnSliderMove</tt> -- raised when the slider is moved.
- * # <tt>OnSliderChanged</tt> -- raised when the slider value is changed
- *
- * You can attach custom javascript code to each of these events
- *
- * @return TSliderClientScript javascript validator event options.
- */
- public function getClientSide()
- {
- if($this->_clientScript===null)
- $this->_clientScript = $this->createClientScript();
- return $this->_clientScript;
- }
-
- /**
- * @return TSliderClientScript javascript event options.
- */
- protected function createClientScript()
- {
- return new TSliderClientScript;
- }
-
- /**
- * @return string the HTML tag name for slider. Defaults to div.
- */
- public function getTagName ()
- {
- return "div";
- }
-
- /**
- * Add the specified css classes to the track
- * @param THtmlWriter writer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id',$this->getClientID());
- if ($this->getCssClass()==='')
- {
- $class=($this->getDirection()==TSliderDirection::Horizontal)?'HorizontalSlider':'VerticalSlider';
- $writer->addAttribute('class', 'Slider '.$class);
- }
-
- }
-
- /**
- * Render the body content
- */
- public function renderContents($writer)
- {
- // Render the 'Track'
- $writer->addAttribute('class', 'Track');
- $writer->addAttribute('id', $this->getClientID().'_track');
- $writer->renderBeginTag('div');
- // Render the 'Progress Indicator'
- if ($this->getProgressIndicator())
- {
- $writer->addAttribute('class', 'Progress');
- $writer->addAttribute('id', $this->getClientID().'_progress');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- // Render the 'Ruler'
- /*
- * Removing for now
- $writer->addAttribute('class', 'RuleContainer');
- $writer->addAttribute('id', $this->getClientID()."_rule");
- $writer->renderBeginTag('div');
- for ($i=0;$i<=100;$i+=10)
- {
- $writer->addAttribute('class', 'RuleMark');
- $attr=($this->getDirection()===TSliderDirection::Horizontal)?"left":"top";
- $writer->addStyleAttribute($attr, $i.'%');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- $writer->renderEndTag();
- */
-
- $writer->renderEndTag();
-
- // Render the 'Handle'
- $writer->addAttribute('class', 'Handle');
- $writer->addAttribute('id', $this->getClientID().'_handle');
- $writer->renderBeginTag('div');
- $writer->renderEndTag();
- }
- /**
- * Registers CSS and JS.
- * This method is invoked right before the control rendering, if the control is visible.
- * @param mixed event parameter
- */
- public function onPreRender ($param)
- {
- parent::onPreRender($param);
- $this->registerStyleSheet();
- $this->registerSliderClientScript();
-
- }
-
- /**
- * Registers the CSS relevant to the TSlider.
- * It will register the CSS file specified by {@link getCssUrl CssUrl}.
- * If that is not set, it will use the default CSS.
- */
- protected function registerStyleSheet()
- {
- if(($url=$this->getCssUrl())==='')
- {
- $manager=$this->getApplication()->getAssetManager();
- // publish the assets
- $url=$manager->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'TSlider');
- $url.='/TSlider.css';
- }
- $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
- }
-
- /**
- * Registers the javascript code to initialize the slider.
- */
- protected function registerSliderClientScript()
- {
- $page=$this->getPage();
- $cs = $page->getClientScript();
- $cs->registerPradoScript("slider");
- $id=$this->getClientID();
- $cs->registerHiddenField($id.'_1',$this->getValue());
- $page->registerRequiresPostData($this);
- $cs->registerPostBackControl($this->getClientClassName(),$this->getSliderOptions());
- }
-
- /**
- * Get javascript sliderr options.
- * @return array slider client-side options
- */
- protected function getSliderOptions()
- {
- // PostBack Options :
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['AutoPostBack'] = $this->getAutoPostBack();
-
- // Slider Control options
- $minValue=$this->getMinValue();
- $maxValue=$this->getMaxValue();
- $options['axis'] = strtolower($this->getDirection());
- $options['maximum'] = $maxValue;
- $options['minimum'] = $minValue;
- $options['range'] = TJavascript::quoteJsLiteral('$R('.$minValue.",".$maxValue.")");
- $options['sliderValue'] = $this->getValue();
- $options['disabled'] = !$this->getEnabled();
- $values=$this->getValues();
- if (!empty($values))
- {
- // Values are provided. Check if min/max are present in them
- if (!in_array($minValue, $values)) $values[]=$minValue;
- if (!in_array($maxValue, $values)) $values[]=$maxValue;
- // Remove all values outsize the range [min..max]
- foreach ($values as $idx=>$value)
- {
- if ($value < $minValue) unset ($values[$idx]);
- if ($value > $maxValue) unset ($values[$idx]);
- }
- }
- else
- {
- // Values are not provided, generate automatically using stepsize
- $step=$this->getStepSize();
- // We want at most self::MAX_STEPS values, so, change the step if necessary
- if (($maxValue-$minValue)/$step > self::MAX_STEPS)
- {
- $step=($maxValue-$minValue)/self::MAX_STEPS;
- }
- $values=array();
- for ($i=$minValue;$i<=$maxValue;$i+=$step)
- $values[]=$i;
- // Add max if it's not in the array because of step
- if (!in_array($maxValue, $values)) $values[]=$maxValue;
- }
- $options['values'] = $values;
- if($this->_clientScript!==null)
- $options = array_merge($options,$this->_clientScript->getOptions()->toArray());
- return $options;
- }
-}
-
-/**
- * TSliderClientScript class.
- *
- * Client-side slider events {@link setOnChange OnChange} and {@line setOnMove OnMove}
- * can be modified through the {@link TSlider:: getClientSide ClientSide}
- * property of a slider.
- *
- * The current value of the slider can be get in the 'value' js variable
- *
- * The <tt>OnMove</tt> event is raised when the slider moves
- * The <tt>OnChange</tt> event is raised when the slider value is changed (or at the end of a move)
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSliderClientScript extends TClientSideOptions
-{
- /**
- * Javascript code to execute when the slider value is changed.
- * @param string javascript code
- */
- public function setOnChange($javascript)
- {
- $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
- $this->setFunction('onChange', $code);
- }
-
- /**
- * @return string javascript code to execute when the slider value is changed.
- */
- public function getOnChange()
- {
- return $this->getOption('onChange');
- }
-
- /* Javascript code to execute when the slider moves.
- * @param string javascript code
- */
- public function setOnSlide($javascript)
- {
- $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
- $this->setFunction('onSlide', $code);
- }
-
- /**
- * @return string javascript code to execute when the slider moves.
- */
- public function getOnSlide()
- {
- return $this->getOption('onSlide');
- }
-}
-
-
-/**
- * TSliderDirection class.
- *
- * TSliderDirection defines the enumerable type for the possible direction that can be used in a {@link TSlider}
- *
- * The following enumerable values are defined :
- * - Horizontal : Horizontal slider
- * - Vertical : Vertical slider
- *
- * @author Christophe Boulain <Christophe.Boulain@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1.1
- */
-class TSliderDirection extends TEnumerable
-{
- const Horizontal='Horizontal';
- const Vertical='Vertical';
-}
-
-
+<?php
+/**
+ * TSlider class file.
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+
+/**
+ * TSlider class
+ *
+ * TSlider displays a slider for numeric input purpose. A slider consists of a 'track',
+ * which define the range of possible value, and a 'handle' which can slide on the track, to select
+ * a value in the range. The track can be either Horizontal or Vertical, depending of the {@link SetDirection Direction}
+ * property. By default, it's horizontal.
+ *
+ * The range boundaries are defined by {@link SetMinValue MinValue} and {@link SetMaxValue MaxValue} properties.
+ * The default range is from 0 to 100.
+ * The {@link SetStepSize StepSize} property can be used to define the <b>step</b> between 2 values inside the range.
+ * Notice that this step will be recomputed if there is more than 200 values between the range boundaries.
+ * You can also provide the allowed values by setting the {@link SetValues Values} array.
+ *
+ * A 'Progress Indicator' can be displayed within the track with the {@link SetProgressIndicator ProgressIndicator} property.
+ *
+ * The TSlider control can be easily customized using CssClasses. You can provide your own css file, using the
+ * {@link SetCssUrl CssUrl} property.
+ * The css class for TSlider can be set by the {@link setCssClass CssClass} property. Default value is "Slider HorizontalSlider"
+ * for an horizontal slider, and "Slider VerticalSlider" for a vertical one.
+ *
+ * If {@link SetAutoPostBack AutoPostBack} property is true, postback is sent as soon as the value changed.
+ *
+ * TSlider raises the {@link onValueChanged} event when the value of the slider has changed during postback.
+ *
+ * You can also attach ClientSide javascript events handler to the slider :
+ * - ClientSide.onSlide is called when the handle is slided on the track. You can get the current value in the <b>value</b>
+ * javascript variable. You can use this event to update on client side a label with the current value
+ * - ClientSide.onChange is called when the slider value has changed (at the end of a move).
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSlider extends TWebControl implements IPostBackDataHandler, IDataRenderer
+{
+ const MAX_STEPS=200;
+ /**
+ * @var TSliderHandle handle component
+ */
+ private $_handle;
+ /*
+ * @var boolean Wether the data has changed during postback
+ */
+ private $_dataChanged=false;
+ /**
+ * @var TSliderClientScript Clients side javascripts
+ */
+ private $_clientScript=null;
+
+ /**
+ * @return TSliderDirection Direction of slider (Horizontal or Vertical). Defaults to Horizontal.
+ */
+ public function getDirection()
+ {
+ return $this->getViewState('Direction', TSliderDirection::Horizontal);
+ }
+
+ /**
+ * @param TSliderDirection Direction of slider (Horizontal or Vertical)
+ */
+ public function setDirection($value)
+ {
+ $this->setViewState('Direction', TPropertyValue::ensureEnum($value,'TSliderDirection'),TSliderDirection::Horizontal);
+ }
+
+ /**
+ * @return string URL for the CSS file including all relevant CSS class definitions. Defaults to '' (a default CSS file will be applied in this case.)
+ */
+ public function getCssUrl()
+ {
+ return $this->getViewState('CssUrl','');
+ }
+
+ /**
+ * @param string URL for the CSS file including all relevant CSS class definitions.
+ */
+ public function setCssUrl($value)
+ {
+ $this->setViewState('CssUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return float Maximum value for the slider. Defaults to 100.0.
+ */
+ public function getMaxValue()
+ {
+ return $this->getViewState('MaxValue',100.0);
+ }
+
+ /**
+ * @param float Maximum value for slider
+ */
+ public function setMaxValue($value)
+ {
+ $this->setViewState('MaxValue', TPropertyValue::ensureFloat($value),100.0);
+ }
+
+ /**
+ * @return float Minimum value for slider. Defaults to 0.0.
+ */
+ public function getMinValue()
+ {
+ return $this->getViewState('MinValue',0.0);
+ }
+
+ /**
+ * @param float Minimum value for slider
+ */
+ public function setMinValue($value)
+ {
+ $this->setViewState('MinValue', TPropertyValue::ensureFloat($value),0.0);
+ }
+
+ /**
+ * @return float Step size. Defaults to 1.0.
+ */
+ public function getStepSize()
+ {
+ return $this->getViewState('StepSize', 1.0);
+ }
+
+ /**
+ * Sets the step size used to determine the places where the slider handle can stop at.
+ * An evenly distributed stop marks will be generated according to
+ * {@link getMinValue MinValue}, {@link getMaxValue MaxValue} and StepSize.
+ * To use uneven stop marks, set {@link setValues Values}.
+ * @param float Step size.
+ */
+ public function setStepSize($value)
+ {
+ $this->setViewState('StepSize', $value, 1.0);
+ }
+
+ /**
+ * @return boolean wether to display a progress indicator or not. Defaults to true.
+ */
+ public function getProgressIndicator ()
+ {
+ return $this->getViewState('ProgressIndicator', true);
+ }
+
+ /**
+ * @param boolean wether to display a progress indicator or not. Defaults to true.
+ */
+ public function setProgressIndicator ($value)
+ {
+ $this->setViewState('ProgressIndicator', TPropertyValue::ensureBoolean($value), true);
+ }
+ /**
+ * @return float current value of slider
+ */
+ public function getValue()
+ {
+ return $this->getViewState('Value',0.0);
+ }
+
+ /**
+ * @param float current value of slider
+ */
+ public function setValue($value)
+ {
+ $this->setViewState('Value', TPropertyValue::ensureFloat($value),0.0);
+ }
+
+ /**
+ * Returns the value of the TSlider control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getValue()}.
+ * @return string the value of the TSlider control.
+ * @see getValue
+ */
+ public function getData()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Sets the value of the TSlider control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setValue()}.
+ * @param string the value of the TSlider control.
+ * @see setValue
+ */
+ public function setData($value)
+ {
+ $this->setValue($value);
+ }
+
+ /**
+ * @return array list of allowed values the slider can take. Defaults to an empty array.
+ */
+ public function getValues()
+ {
+ return $this->getViewState('Values', array());
+ }
+
+ /**
+ * Sets the possible values that the slider can take.
+ * If this is set, {@link setStepSize StepSize} will be ignored. The latter
+ * generates a set of evenly distributed candidate values.
+ * @param array list of allowed values the slider can take
+ */
+ public function setValues($value)
+ {
+ $this->setViewState('Values', TPropertyValue::ensureArray($value), array());
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user modifies the slider value. Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * modifies the slider value.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TSlider';
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getValue Value} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ $this->onValueChanged(null);
+ }
+
+ /**
+ * Raises <b>OnValueChanged</b> event.
+ * This method is invoked when the {@link getValue Value}
+ * property changes on postback.
+ * If you override this method, be sure to call the parent implementation to ensure
+ * the invocation of the attached event handlers.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onValueChanged($param)
+ {
+ $this->raiseEvent('OnValueChanged',$this,$param);
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=(float)$values[$this->getClientID().'_1'];
+ if($this->getValue()!==$value)
+ {
+ $this->setValue($value);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Gets the TSliderClientScript to set the TSlider event handlers.
+ *
+ * The slider on the client-side supports the following events.
+ * # <tt>OnSliderMove</tt> -- raised when the slider is moved.
+ * # <tt>OnSliderChanged</tt> -- raised when the slider value is changed
+ *
+ * You can attach custom javascript code to each of these events
+ *
+ * @return TSliderClientScript javascript validator event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientScript===null)
+ $this->_clientScript = $this->createClientScript();
+ return $this->_clientScript;
+ }
+
+ /**
+ * @return TSliderClientScript javascript event options.
+ */
+ protected function createClientScript()
+ {
+ return new TSliderClientScript;
+ }
+
+ /**
+ * @return string the HTML tag name for slider. Defaults to div.
+ */
+ public function getTagName ()
+ {
+ return "div";
+ }
+
+ /**
+ * Add the specified css classes to the track
+ * @param THtmlWriter writer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $writer->addAttribute('id',$this->getClientID());
+ if ($this->getCssClass()==='')
+ {
+ $class=($this->getDirection()==TSliderDirection::Horizontal)?'HorizontalSlider':'VerticalSlider';
+ $writer->addAttribute('class', 'Slider '.$class);
+ }
+
+ }
+
+ /**
+ * Render the body content
+ */
+ public function renderContents($writer)
+ {
+ // Render the 'Track'
+ $writer->addAttribute('class', 'Track');
+ $writer->addAttribute('id', $this->getClientID().'_track');
+ $writer->renderBeginTag('div');
+ // Render the 'Progress Indicator'
+ if ($this->getProgressIndicator())
+ {
+ $writer->addAttribute('class', 'Progress');
+ $writer->addAttribute('id', $this->getClientID().'_progress');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ // Render the 'Ruler'
+ /*
+ * Removing for now
+ $writer->addAttribute('class', 'RuleContainer');
+ $writer->addAttribute('id', $this->getClientID()."_rule");
+ $writer->renderBeginTag('div');
+ for ($i=0;$i<=100;$i+=10)
+ {
+ $writer->addAttribute('class', 'RuleMark');
+ $attr=($this->getDirection()===TSliderDirection::Horizontal)?"left":"top";
+ $writer->addStyleAttribute($attr, $i.'%');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ $writer->renderEndTag();
+ */
+
+ $writer->renderEndTag();
+
+ // Render the 'Handle'
+ $writer->addAttribute('class', 'Handle');
+ $writer->addAttribute('id', $this->getClientID().'_handle');
+ $writer->renderBeginTag('div');
+ $writer->renderEndTag();
+ }
+ /**
+ * Registers CSS and JS.
+ * This method is invoked right before the control rendering, if the control is visible.
+ * @param mixed event parameter
+ */
+ public function onPreRender ($param)
+ {
+ parent::onPreRender($param);
+ $this->registerStyleSheet();
+ $this->registerSliderClientScript();
+
+ }
+
+ /**
+ * Registers the CSS relevant to the TSlider.
+ * It will register the CSS file specified by {@link getCssUrl CssUrl}.
+ * If that is not set, it will use the default CSS.
+ */
+ protected function registerStyleSheet()
+ {
+ if(($url=$this->getCssUrl())==='')
+ {
+ $manager=$this->getApplication()->getAssetManager();
+ // publish the assets
+ $url=$manager->publishFilePath(dirname(__FILE__).DIRECTORY_SEPARATOR.'assets'.DIRECTORY_SEPARATOR.'TSlider');
+ $url.='/TSlider.css';
+ }
+ $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url);
+ }
+
+ /**
+ * Registers the javascript code to initialize the slider.
+ */
+ protected function registerSliderClientScript()
+ {
+ $page=$this->getPage();
+ $cs = $page->getClientScript();
+ $cs->registerPradoScript("slider");
+ $id=$this->getClientID();
+ $cs->registerHiddenField($id.'_1',$this->getValue());
+ $page->registerRequiresPostData($this);
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getSliderOptions());
+ }
+
+ /**
+ * Get javascript sliderr options.
+ * @return array slider client-side options
+ */
+ protected function getSliderOptions()
+ {
+ // PostBack Options :
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+
+ // Slider Control options
+ $minValue=$this->getMinValue();
+ $maxValue=$this->getMaxValue();
+ $options['axis'] = strtolower($this->getDirection());
+ $options['maximum'] = $maxValue;
+ $options['minimum'] = $minValue;
+ $options['range'] = TJavascript::quoteJsLiteral('$R('.$minValue.",".$maxValue.")");
+ $options['sliderValue'] = $this->getValue();
+ $options['disabled'] = !$this->getEnabled();
+ $values=$this->getValues();
+ if (!empty($values))
+ {
+ // Values are provided. Check if min/max are present in them
+ if (!in_array($minValue, $values)) $values[]=$minValue;
+ if (!in_array($maxValue, $values)) $values[]=$maxValue;
+ // Remove all values outsize the range [min..max]
+ foreach ($values as $idx=>$value)
+ {
+ if ($value < $minValue) unset ($values[$idx]);
+ if ($value > $maxValue) unset ($values[$idx]);
+ }
+ }
+ else
+ {
+ // Values are not provided, generate automatically using stepsize
+ $step=$this->getStepSize();
+ // We want at most self::MAX_STEPS values, so, change the step if necessary
+ if (($maxValue-$minValue)/$step > self::MAX_STEPS)
+ {
+ $step=($maxValue-$minValue)/self::MAX_STEPS;
+ }
+ $values=array();
+ for ($i=$minValue;$i<=$maxValue;$i+=$step)
+ $values[]=$i;
+ // Add max if it's not in the array because of step
+ if (!in_array($maxValue, $values)) $values[]=$maxValue;
+ }
+ $options['values'] = $values;
+ if($this->_clientScript!==null)
+ $options = array_merge($options,$this->_clientScript->getOptions()->toArray());
+ return $options;
+ }
+}
+
+/**
+ * TSliderClientScript class.
+ *
+ * Client-side slider events {@link setOnChange OnChange} and {@line setOnMove OnMove}
+ * can be modified through the {@link TSlider:: getClientSide ClientSide}
+ * property of a slider.
+ *
+ * The current value of the slider can be get in the 'value' js variable
+ *
+ * The <tt>OnMove</tt> event is raised when the slider moves
+ * The <tt>OnChange</tt> event is raised when the slider value is changed (or at the end of a move)
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSliderClientScript extends TClientSideOptions
+{
+ /**
+ * Javascript code to execute when the slider value is changed.
+ * @param string javascript code
+ */
+ public function setOnChange($javascript)
+ {
+ $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
+ $this->setFunction('onChange', $code);
+ }
+
+ /**
+ * @return string javascript code to execute when the slider value is changed.
+ */
+ public function getOnChange()
+ {
+ return $this->getOption('onChange');
+ }
+
+ /* Javascript code to execute when the slider moves.
+ * @param string javascript code
+ */
+ public function setOnSlide($javascript)
+ {
+ $code=TJavascript::quoteJsLiteral("function (value) { {$javascript} }");
+ $this->setFunction('onSlide', $code);
+ }
+
+ /**
+ * @return string javascript code to execute when the slider moves.
+ */
+ public function getOnSlide()
+ {
+ return $this->getOption('onSlide');
+ }
+}
+
+
+/**
+ * TSliderDirection class.
+ *
+ * TSliderDirection defines the enumerable type for the possible direction that can be used in a {@link TSlider}
+ *
+ * The following enumerable values are defined :
+ * - Horizontal : Horizontal slider
+ * - Vertical : Vertical slider
+ *
+ * @author Christophe Boulain <Christophe.Boulain@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1.1
+ */
+class TSliderDirection extends TEnumerable
+{
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+}
+
+
diff --git a/framework/Web/UI/WebControls/TStatements.php b/framework/Web/UI/WebControls/TStatements.php
index c3f43278..dd7631e2 100644
--- a/framework/Web/UI/WebControls/TStatements.php
+++ b/framework/Web/UI/WebControls/TStatements.php
@@ -1,63 +1,63 @@
-<?php
-/**
- * TStatements class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TStatements class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TStatements class
- *
- * TStatements executes one or several PHP statements and renders the display
- * generated during the execution. The execution happens during the rendering stage.
- * The PHP statements being executed can be set via the property
- * {@link setStatements Statements}. The context of the statemenets executed
- * is the TStatements object itself.
- *
- * Note, since TStatements allows execution of arbitrary PHP statements,
- * make sure {@link setStatements Statements} does not come directly from user input.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TStatements extends TControl
-{
- /**
- * @var string PHP statements
- */
- private $_s='';
-
- /**
- * @return string the statements to be executed
- */
- public function getStatements()
- {
- return $this->_s;
- }
-
- /**
- * @param string the PHP statements to be executed
- */
- public function setStatements($value)
- {
- $this->_s=$value;
- }
-
- /**
- * Renders the evaluation result of the statements.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function render($writer)
- {
- if($this->_s!=='')
- $writer->write($this->evaluateStatements($this->_s));
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TStatements class
+ *
+ * TStatements executes one or several PHP statements and renders the display
+ * generated during the execution. The execution happens during the rendering stage.
+ * The PHP statements being executed can be set via the property
+ * {@link setStatements Statements}. The context of the statemenets executed
+ * is the TStatements object itself.
+ *
+ * Note, since TStatements allows execution of arbitrary PHP statements,
+ * make sure {@link setStatements Statements} does not come directly from user input.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TStatements extends TControl
+{
+ /**
+ * @var string PHP statements
+ */
+ private $_s='';
+
+ /**
+ * @return string the statements to be executed
+ */
+ public function getStatements()
+ {
+ return $this->_s;
+ }
+
+ /**
+ * @param string the PHP statements to be executed
+ */
+ public function setStatements($value)
+ {
+ $this->_s=$value;
+ }
+
+ /**
+ * Renders the evaluation result of the statements.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function render($writer)
+ {
+ if($this->_s!=='')
+ $writer->write($this->evaluateStatements($this->_s));
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TStyle.php b/framework/Web/UI/WebControls/TStyle.php
index 58be223a..93f7d45d 100644
--- a/framework/Web/UI/WebControls/TStyle.php
+++ b/framework/Web/UI/WebControls/TStyle.php
@@ -1,893 +1,893 @@
-<?php
-/**
- * TStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TFont definition
- */
-Prado::using('System.Web.UI.WebControls.TFont');
-
-/**
- * TStyle class
- *
- * TStyle encapsulates the CSS style applied to a control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TStyle extends TComponent
-{
- /**
- * @var array storage of CSS fields
- */
- private $_fields=array();
- /**
- * @var TFont font object
- */
- private $_font=null;
- /**
- * @var string CSS class name
- */
- private $_class=null;
- /**
- * @var string CSS style string (those not represented by specific fields of TStyle)
- */
- private $_customStyle=null;
- /**
- * @var string display style
- */
- private $_displayStyle='Fixed';
-
- /**
- * Constructor.
- * @param TStyle style to copy from
- */
- public function __construct($style=null)
- {
- if($style!==null)
- $this->copyFrom($style);
- }
-
- /**
- * Need to clone the font object.
- */
- public function __clone()
- {
- if($this->_font!==null)
- $this->_font = clone($this->_font);
- }
-
- /**
- * @return string the background color of the control
- */
- public function getBackColor()
- {
- return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
- }
-
- /**
- * @param string the background color of the control
- */
- public function setBackColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['background-color']);
- else
- $this->_fields['background-color']=$value;
- }
-
- /**
- * @return string the border color of the control
- */
- public function getBorderColor()
- {
- return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
- }
-
- /**
- * @param string the border color of the control
- */
- public function setBorderColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-color']);
- else
- $this->_fields['border-color']=$value;
- }
-
- /**
- * @return string the border style of the control
- */
- public function getBorderStyle()
- {
- return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
- }
-
- /**
- * Sets the border style of the control.
- * @param string the border style of the control
- */
- public function setBorderStyle($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-style']);
- else
- $this->_fields['border-style']=$value;
- }
-
- /**
- * @return string the border width of the control
- */
- public function getBorderWidth()
- {
- return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
- }
-
- /**
- * @param string the border width of the control
- */
- public function setBorderWidth($value)
- {
- if(trim($value)==='')
- unset($this->_fields['border-width']);
- else
- $this->_fields['border-width']=$value;
- }
-
- /**
- * @return string the CSS class of the control
- */
- public function getCssClass()
- {
- return $this->_class===null?'':$this->_class;
- }
-
- /**
- * @return boolean true if CSS is set or empty.
- */
- public function hasCssClass()
- {
- return ($this->_class!==null);
- }
-
- /**
- * @param string the name of the CSS class of the control
- */
- public function setCssClass($value)
- {
- $this->_class=$value;
- }
-
- /**
- * @return TFont the font of the control
- */
- public function getFont()
- {
- if($this->_font===null)
- $this->_font=new TFont;
- return $this->_font;
- }
-
- /**
- * @return boolean true if font is set.
- */
- public function hasFont()
- {
- return $this->_font !== null;
- }
-
- /**
- * @param TDisplayStyle control display style, default is TDisplayStyle::Fixed
- */
- public function setDisplayStyle($value)
- {
- $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
- switch($this->_displayStyle)
- {
- case TDisplayStyle::None:
- $this->_fields['display'] = 'none';
- break;
- case TDisplayStyle::Dynamic:
- $this->_fields['display'] = ''; //remove the display property
- break;
- case TDisplayStyle::Fixed:
- $this->_fields['visibility'] = 'visible';
- break;
- case TDisplayStyle::Hidden:
- $this->_fields['visibility'] = 'hidden';
- break;
- }
- }
-
- /**
- * @return TDisplayStyle display style
- */
- public function getDisplayStyle()
- {
- return $this->_displayStyle;
- }
-
- /**
- * @return string the foreground color of the control
- */
- public function getForeColor()
- {
- return isset($this->_fields['color'])?$this->_fields['color']:'';
- }
-
- /**
- * @param string the foreground color of the control
- */
- public function setForeColor($value)
- {
- if(trim($value)==='')
- unset($this->_fields['color']);
- else
- $this->_fields['color']=$value;
- }
-
- /**
- * @return string the height of the control
- */
- public function getHeight()
- {
- return isset($this->_fields['height'])?$this->_fields['height']:'';
- }
-
- /**
- * @param string the height of the control
- */
- public function setHeight($value)
- {
- if(trim($value)==='')
- unset($this->_fields['height']);
- else
- $this->_fields['height']=$value;
- }
-
- /**
- * @return string the custom style of the control
- */
- public function getCustomStyle()
- {
- return $this->_customStyle===null?'':$this->_customStyle;
- }
-
- /**
- * Sets custom style fields from a string.
- * Custom style fields will be overwritten by style fields explicitly defined.
- * @param string the custom style of the control
- */
- public function setCustomStyle($value)
- {
- $this->_customStyle=$value;
- }
-
- /**
- * @return string a single style field value set via {@link setStyleField}. Defaults to empty string.
- */
- public function getStyleField($name)
- {
- return isset($this->_fields[$name])?$this->_fields[$name]:'';
- }
-
- /**
- * Sets a single style field value.
- * Style fields set by this method will overwrite those set by {@link setCustomStyle}.
- * @param string style field name
- * @param string style field value
- */
- public function setStyleField($name,$value)
- {
- $this->_fields[$name]=$value;
- }
-
- /**
- * Clears a single style field value;
- * @param string style field name
- */
- public function clearStyleField($name)
- {
- unset($this->_fields[$name]);
- }
-
- /**
- * @return boolean whether a style field has been defined by {@link setStyleField}
- */
- public function hasStyleField($name)
- {
- return isset($this->_fields[$name]);
- }
-
- /**
- * @return string the width of the control
- */
- public function getWidth()
- {
- return isset($this->_fields['width'])?$this->_fields['width']:'';
- }
-
- /**
- * @param string the width of the control
- */
- public function setWidth($value)
- {
- $this->_fields['width']=$value;
- }
-
- /**
- * Resets the style to the original empty state.
- */
- public function reset()
- {
- $this->_fields=array();
- $this->_font=null;
- $this->_class=null;
- $this->_customStyle=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- if($style instanceof TStyle)
- {
- $this->_fields=array_merge($this->_fields,$style->_fields);
- if($style->_class!==null)
- $this->_class=$style->_class;
- if($style->_customStyle!==null)
- $this->_customStyle=$style->_customStyle;
- if($style->_font!==null)
- $this->getFont()->copyFrom($style->_font);
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- if($style instanceof TStyle)
- {
- $this->_fields=array_merge($style->_fields,$this->_fields);
- if($this->_class===null)
- $this->_class=$style->_class;
- if($this->_customStyle===null)
- $this->_customStyle=$style->_customStyle;
- if($style->_font!==null)
- $this->getFont()->mergeWith($style->_font);
- }
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if($this->_customStyle!==null)
- {
- foreach(explode(';',$this->_customStyle) as $style)
- {
- $arr=explode(':',$style,2);
- if(isset($arr[1]) && trim($arr[0])!=='')
- $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
- }
- }
- $writer->addStyleAttributes($this->_fields);
- if($this->_font!==null)
- $this->_font->addAttributesToRender($writer);
- if($this->_class!==null)
- $writer->addAttribute('class',$this->_class);
- }
-
- /**
- * @return array list of style fields.
- */
- public function getStyleFields()
- {
- return $this->_fields;
- }
-}
-
-/**
- * TDisplayStyle defines the enumerable type for the possible styles
- * that a web control can display.
- *
- * The following enumerable values are defined:
- * - None: the control is not displayed and not included in the layout.
- * - Dynamic: the control is displayed and included in the layout, the layout flow is dependent on the control (equivalent to display:'' in css).
- * - Fixed: Similar to Dynamic with CSS "visibility" set "shown".
- * - Hidden: the control is not displayed and is included in the layout.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.1
- */
-class TDisplayStyle extends TEnumerable
-{
- const None='None';
- const Dynamic='Dynamic';
- const Fixed='Fixed';
- const Hidden='Hidden';
-}
-
-/**
- * TTableStyle class.
- * TTableStyle represents the CSS style specific for HTML table.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableStyle extends TStyle
-{
- /**
- * @var TVerticalAlign the URL of the background image for the table
- */
- private $_backImageUrl=null;
- /**
- * @var THorizontalAlign horizontal alignment of the contents within the table
- */
- private $_horizontalAlign=null;
- /**
- * @var integer cellpadding of the table
- */
- private $_cellPadding=null;
- /**
- * @var integer cellspacing of the table
- */
- private $_cellSpacing=null;
- /**
- * @var TTableGridLines grid line setting of the table
- */
- private $_gridLines=null;
- /**
- * @var boolean whether the table border should be collapsed
- */
- private $_borderCollapse=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TTableStyle specific attributes.
- */
- public function reset()
- {
- $this->_backImageUrl=null;
- $this->_horizontalAlign=null;
- $this->_cellPadding=null;
- $this->_cellSpacing=null;
- $this->_gridLines=null;
- $this->_borderCollapse=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TTableStyle)
- {
- if($style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_cellPadding!==null)
- $this->_cellPadding=$style->_cellPadding;
- if($style->_cellSpacing!==null)
- $this->_cellSpacing=$style->_cellSpacing;
- if($style->_gridLines!==null)
- $this->_gridLines=$style->_gridLines;
- if($style->_borderCollapse!==null)
- $this->_borderCollapse=$style->_borderCollapse;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TTableStyle)
- {
- if($this->_backImageUrl===null && $style->_backImageUrl!==null)
- $this->_backImageUrl=$style->_backImageUrl;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_cellPadding===null && $style->_cellPadding!==null)
- $this->_cellPadding=$style->_cellPadding;
- if($this->_cellSpacing===null && $style->_cellSpacing!==null)
- $this->_cellSpacing=$style->_cellSpacing;
- if($this->_gridLines===null && $style->_gridLines!==null)
- $this->_gridLines=$style->_gridLines;
- if($this->_borderCollapse===null && $style->_borderCollapse!==null)
- $this->_borderCollapse=$style->_borderCollapse;
- }
- }
-
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(($url=trim($this->getBackImageUrl()))!=='')
- $writer->addStyleAttribute('background-image','url('.$url.')');
-
- if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
-
- if(($cellPadding=$this->getCellPadding())>=0)
- $writer->addAttribute('cellpadding',"$cellPadding");
-
- if(($cellSpacing=$this->getCellSpacing())>=0)
- $writer->addAttribute('cellspacing',"$cellSpacing");
-
- if($this->getBorderCollapse())
- $writer->addStyleAttribute('border-collapse','collapse');
-
- switch($this->getGridLines())
- {
- case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
- case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
- case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
- }
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return string the URL of the background image for the table
- */
- public function getBackImageUrl()
- {
- return $this->_backImageUrl===null?'':$this->_backImageUrl;
- }
-
- /**
- * Sets the URL of the background image for the table
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->_backImageUrl=$value;
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the table, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return integer cellpadding of the table. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- return $this->_cellPadding===null?-1:$this->_cellPadding;
- }
-
- /**
- * @param integer cellpadding of the table. A value equal to -1 clears up the setting.
- * @throws TInvalidDataValueException if the value is less than -1.
- */
- public function setCellPadding($value)
- {
- if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
- throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
- }
-
- /**
- * @return integer cellspacing of the table. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- return $this->_cellSpacing===null?-1:$this->_cellSpacing;
- }
-
- /**
- * @param integer cellspacing of the table. A value equal to -1 clears up the setting.
- * @throws TInvalidDataValueException if the value is less than -1.
- */
- public function setCellSpacing($value)
- {
- if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
- throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
- }
-
- /**
- * Sets the grid line style of the table.
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
- }
-
-
- /**
- * @return boolean whether the table borders should be collapsed. Defaults to false.
- */
- public function getBorderCollapse()
- {
- return $this->_borderCollapse===null?false:$this->_borderCollapse;
- }
-
- /**
- * @param boolean whether the table borders should be collapsed.
- */
- public function setBorderCollapse($value)
- {
- $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * TTableItemStyle class.
- * TTableItemStyle represents the CSS style specific for HTML table item.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableItemStyle extends TStyle
-{
- /**
- * @var THorizontalAlign horizontal alignment of the contents within the table item
- */
- private $_horizontalAlign=null;
- /**
- * @var TVerticalAlign vertical alignment of the contents within the table item
- */
- private $_verticalAlign=null;
- /**
- * @var boolean whether the content wraps within the table item
- */
- private $_wrap=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TTableItemStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_verticalAlign=null;
- $this->_horizontalAlign=null;
- $this->_wrap=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TTableItemStyle)
- {
- if($this->_verticalAlign===null && $style->_verticalAlign!==null)
- $this->_verticalAlign=$style->_verticalAlign;
- if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($this->_wrap===null && $style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TTableItemStyle)
- {
- if($style->_verticalAlign!==null)
- $this->_verticalAlign=$style->_verticalAlign;
- if($style->_horizontalAlign!==null)
- $this->_horizontalAlign=$style->_horizontalAlign;
- if($style->_wrap!==null)
- $this->_wrap=$style->_wrap;
- }
- }
-
- /**
- * Adds attributes related to CSS styles to renderer.
- * This method overrides the parent implementation.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function addAttributesToRender($writer)
- {
- if(!$this->getWrap())
- $writer->addStyleAttribute('white-space','nowrap');
-
- if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
- $writer->addAttribute('align',strtolower($horizontalAlign));
-
- if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
- $writer->addAttribute('valign',strtolower($verticalAlign));
-
- parent::addAttributesToRender($writer);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the contents within the table item, defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * @param THorizontalAlign the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
- }
-
- /**
- * @return TVerticalAlign the vertical alignment of the contents within the table item, defaults to TVerticalAlign::NotSet.
- */
- public function getVerticalAlign()
- {
- return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * @param TVerticalAlign the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
- }
-
- /**
- * @return boolean whether the content wraps within the table item. Defaults to true.
- */
- public function getWrap()
- {
- return $this->_wrap===null?true:$this->_wrap;
- }
-
- /**
- * Sets the value indicating whether the content wraps within the table item.
- * @param boolean whether the content wraps within the panel.
- */
- public function setWrap($value)
- {
- $this->_wrap=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * THorizontalAlign class.
- * THorizontalAlign defines the enumerable type for the possible horizontal alignments in a CSS style.
- *
- * The following enumerable values are defined:
- * - NotSet: the alignment is not specified.
- * - Left: left aligned
- * - Right: right aligned
- * - Center: center aligned
- * - Justify: the begin and end are justified
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class THorizontalAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Left='Left';
- const Right='Right';
- const Center='Center';
- const Justify='Justify';
-}
-
-/**
- * TVerticalAlign class.
- * TVerticalAlign defines the enumerable type for the possible vertical alignments in a CSS style.
- *
- * The following enumerable values are defined:
- * - NotSet: the alignment is not specified.
- * - Top: top aligned
- * - Bottom: bottom aligned
- * - Middle: middle aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TVerticalAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Top='Top';
- const Bottom='Bottom';
- const Middle='Middle';
-}
-
-
-/**
- * TTableGridLines class.
- * TTableGridLines defines the enumerable type for the possible grid line types of an HTML table.
- *
- * The following enumerable values are defined:
- * - None: no grid lines
- * - Horizontal: horizontal grid lines only
- * - Vertical: vertical grid lines only
- * - Both: both horizontal and vertical grid lines are shown
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableGridLines extends TEnumerable
-{
- const None='None';
- const Horizontal='Horizontal';
- const Vertical='Vertical';
- const Both='Both';
-}
-
+<?php
+/**
+ * TStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TFont definition
+ */
+Prado::using('System.Web.UI.WebControls.TFont');
+
+/**
+ * TStyle class
+ *
+ * TStyle encapsulates the CSS style applied to a control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TStyle extends TComponent
+{
+ /**
+ * @var array storage of CSS fields
+ */
+ private $_fields=array();
+ /**
+ * @var TFont font object
+ */
+ private $_font=null;
+ /**
+ * @var string CSS class name
+ */
+ private $_class=null;
+ /**
+ * @var string CSS style string (those not represented by specific fields of TStyle)
+ */
+ private $_customStyle=null;
+ /**
+ * @var string display style
+ */
+ private $_displayStyle='Fixed';
+
+ /**
+ * Constructor.
+ * @param TStyle style to copy from
+ */
+ public function __construct($style=null)
+ {
+ if($style!==null)
+ $this->copyFrom($style);
+ }
+
+ /**
+ * Need to clone the font object.
+ */
+ public function __clone()
+ {
+ if($this->_font!==null)
+ $this->_font = clone($this->_font);
+ }
+
+ /**
+ * @return string the background color of the control
+ */
+ public function getBackColor()
+ {
+ return isset($this->_fields['background-color'])?$this->_fields['background-color']:'';
+ }
+
+ /**
+ * @param string the background color of the control
+ */
+ public function setBackColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['background-color']);
+ else
+ $this->_fields['background-color']=$value;
+ }
+
+ /**
+ * @return string the border color of the control
+ */
+ public function getBorderColor()
+ {
+ return isset($this->_fields['border-color'])?$this->_fields['border-color']:'';
+ }
+
+ /**
+ * @param string the border color of the control
+ */
+ public function setBorderColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-color']);
+ else
+ $this->_fields['border-color']=$value;
+ }
+
+ /**
+ * @return string the border style of the control
+ */
+ public function getBorderStyle()
+ {
+ return isset($this->_fields['border-style'])?$this->_fields['border-style']:'';
+ }
+
+ /**
+ * Sets the border style of the control.
+ * @param string the border style of the control
+ */
+ public function setBorderStyle($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-style']);
+ else
+ $this->_fields['border-style']=$value;
+ }
+
+ /**
+ * @return string the border width of the control
+ */
+ public function getBorderWidth()
+ {
+ return isset($this->_fields['border-width'])?$this->_fields['border-width']:'';
+ }
+
+ /**
+ * @param string the border width of the control
+ */
+ public function setBorderWidth($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['border-width']);
+ else
+ $this->_fields['border-width']=$value;
+ }
+
+ /**
+ * @return string the CSS class of the control
+ */
+ public function getCssClass()
+ {
+ return $this->_class===null?'':$this->_class;
+ }
+
+ /**
+ * @return boolean true if CSS is set or empty.
+ */
+ public function hasCssClass()
+ {
+ return ($this->_class!==null);
+ }
+
+ /**
+ * @param string the name of the CSS class of the control
+ */
+ public function setCssClass($value)
+ {
+ $this->_class=$value;
+ }
+
+ /**
+ * @return TFont the font of the control
+ */
+ public function getFont()
+ {
+ if($this->_font===null)
+ $this->_font=new TFont;
+ return $this->_font;
+ }
+
+ /**
+ * @return boolean true if font is set.
+ */
+ public function hasFont()
+ {
+ return $this->_font !== null;
+ }
+
+ /**
+ * @param TDisplayStyle control display style, default is TDisplayStyle::Fixed
+ */
+ public function setDisplayStyle($value)
+ {
+ $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle');
+ switch($this->_displayStyle)
+ {
+ case TDisplayStyle::None:
+ $this->_fields['display'] = 'none';
+ break;
+ case TDisplayStyle::Dynamic:
+ $this->_fields['display'] = ''; //remove the display property
+ break;
+ case TDisplayStyle::Fixed:
+ $this->_fields['visibility'] = 'visible';
+ break;
+ case TDisplayStyle::Hidden:
+ $this->_fields['visibility'] = 'hidden';
+ break;
+ }
+ }
+
+ /**
+ * @return TDisplayStyle display style
+ */
+ public function getDisplayStyle()
+ {
+ return $this->_displayStyle;
+ }
+
+ /**
+ * @return string the foreground color of the control
+ */
+ public function getForeColor()
+ {
+ return isset($this->_fields['color'])?$this->_fields['color']:'';
+ }
+
+ /**
+ * @param string the foreground color of the control
+ */
+ public function setForeColor($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['color']);
+ else
+ $this->_fields['color']=$value;
+ }
+
+ /**
+ * @return string the height of the control
+ */
+ public function getHeight()
+ {
+ return isset($this->_fields['height'])?$this->_fields['height']:'';
+ }
+
+ /**
+ * @param string the height of the control
+ */
+ public function setHeight($value)
+ {
+ if(trim($value)==='')
+ unset($this->_fields['height']);
+ else
+ $this->_fields['height']=$value;
+ }
+
+ /**
+ * @return string the custom style of the control
+ */
+ public function getCustomStyle()
+ {
+ return $this->_customStyle===null?'':$this->_customStyle;
+ }
+
+ /**
+ * Sets custom style fields from a string.
+ * Custom style fields will be overwritten by style fields explicitly defined.
+ * @param string the custom style of the control
+ */
+ public function setCustomStyle($value)
+ {
+ $this->_customStyle=$value;
+ }
+
+ /**
+ * @return string a single style field value set via {@link setStyleField}. Defaults to empty string.
+ */
+ public function getStyleField($name)
+ {
+ return isset($this->_fields[$name])?$this->_fields[$name]:'';
+ }
+
+ /**
+ * Sets a single style field value.
+ * Style fields set by this method will overwrite those set by {@link setCustomStyle}.
+ * @param string style field name
+ * @param string style field value
+ */
+ public function setStyleField($name,$value)
+ {
+ $this->_fields[$name]=$value;
+ }
+
+ /**
+ * Clears a single style field value;
+ * @param string style field name
+ */
+ public function clearStyleField($name)
+ {
+ unset($this->_fields[$name]);
+ }
+
+ /**
+ * @return boolean whether a style field has been defined by {@link setStyleField}
+ */
+ public function hasStyleField($name)
+ {
+ return isset($this->_fields[$name]);
+ }
+
+ /**
+ * @return string the width of the control
+ */
+ public function getWidth()
+ {
+ return isset($this->_fields['width'])?$this->_fields['width']:'';
+ }
+
+ /**
+ * @param string the width of the control
+ */
+ public function setWidth($value)
+ {
+ $this->_fields['width']=$value;
+ }
+
+ /**
+ * Resets the style to the original empty state.
+ */
+ public function reset()
+ {
+ $this->_fields=array();
+ $this->_font=null;
+ $this->_class=null;
+ $this->_customStyle=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($this->_fields,$style->_fields);
+ if($style->_class!==null)
+ $this->_class=$style->_class;
+ if($style->_customStyle!==null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->copyFrom($style->_font);
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ if($style instanceof TStyle)
+ {
+ $this->_fields=array_merge($style->_fields,$this->_fields);
+ if($this->_class===null)
+ $this->_class=$style->_class;
+ if($this->_customStyle===null)
+ $this->_customStyle=$style->_customStyle;
+ if($style->_font!==null)
+ $this->getFont()->mergeWith($style->_font);
+ }
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if($this->_customStyle!==null)
+ {
+ foreach(explode(';',$this->_customStyle) as $style)
+ {
+ $arr=explode(':',$style,2);
+ if(isset($arr[1]) && trim($arr[0])!=='')
+ $writer->addStyleAttribute(trim($arr[0]),trim($arr[1]));
+ }
+ }
+ $writer->addStyleAttributes($this->_fields);
+ if($this->_font!==null)
+ $this->_font->addAttributesToRender($writer);
+ if($this->_class!==null)
+ $writer->addAttribute('class',$this->_class);
+ }
+
+ /**
+ * @return array list of style fields.
+ */
+ public function getStyleFields()
+ {
+ return $this->_fields;
+ }
+}
+
+/**
+ * TDisplayStyle defines the enumerable type for the possible styles
+ * that a web control can display.
+ *
+ * The following enumerable values are defined:
+ * - None: the control is not displayed and not included in the layout.
+ * - Dynamic: the control is displayed and included in the layout, the layout flow is dependent on the control (equivalent to display:'' in css).
+ * - Fixed: Similar to Dynamic with CSS "visibility" set "shown".
+ * - Hidden: the control is not displayed and is included in the layout.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.1
+ */
+class TDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+ const Hidden='Hidden';
+}
+
+/**
+ * TTableStyle class.
+ * TTableStyle represents the CSS style specific for HTML table.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableStyle extends TStyle
+{
+ /**
+ * @var TVerticalAlign the URL of the background image for the table
+ */
+ private $_backImageUrl=null;
+ /**
+ * @var THorizontalAlign horizontal alignment of the contents within the table
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var integer cellpadding of the table
+ */
+ private $_cellPadding=null;
+ /**
+ * @var integer cellspacing of the table
+ */
+ private $_cellSpacing=null;
+ /**
+ * @var TTableGridLines grid line setting of the table
+ */
+ private $_gridLines=null;
+ /**
+ * @var boolean whether the table border should be collapsed
+ */
+ private $_borderCollapse=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TTableStyle specific attributes.
+ */
+ public function reset()
+ {
+ $this->_backImageUrl=null;
+ $this->_horizontalAlign=null;
+ $this->_cellPadding=null;
+ $this->_cellSpacing=null;
+ $this->_gridLines=null;
+ $this->_borderCollapse=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableStyle)
+ {
+ if($style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableStyle)
+ {
+ if($this->_backImageUrl===null && $style->_backImageUrl!==null)
+ $this->_backImageUrl=$style->_backImageUrl;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_cellPadding===null && $style->_cellPadding!==null)
+ $this->_cellPadding=$style->_cellPadding;
+ if($this->_cellSpacing===null && $style->_cellSpacing!==null)
+ $this->_cellSpacing=$style->_cellSpacing;
+ if($this->_gridLines===null && $style->_gridLines!==null)
+ $this->_gridLines=$style->_gridLines;
+ if($this->_borderCollapse===null && $style->_borderCollapse!==null)
+ $this->_borderCollapse=$style->_borderCollapse;
+ }
+ }
+
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(($url=trim($this->getBackImageUrl()))!=='')
+ $writer->addStyleAttribute('background-image','url('.$url.')');
+
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addStyleAttribute('text-align',strtolower($horizontalAlign));
+
+ if(($cellPadding=$this->getCellPadding())>=0)
+ $writer->addAttribute('cellpadding',"$cellPadding");
+
+ if(($cellSpacing=$this->getCellSpacing())>=0)
+ $writer->addAttribute('cellspacing',"$cellSpacing");
+
+ if($this->getBorderCollapse())
+ $writer->addStyleAttribute('border-collapse','collapse');
+
+ switch($this->getGridLines())
+ {
+ case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break;
+ case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break;
+ case TTableGridLines::Both : $writer->addAttribute('rules','all'); break;
+ }
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return string the URL of the background image for the table
+ */
+ public function getBackImageUrl()
+ {
+ return $this->_backImageUrl===null?'':$this->_backImageUrl;
+ }
+
+ /**
+ * Sets the URL of the background image for the table
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->_backImageUrl=$value;
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the table, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return integer cellpadding of the table. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ return $this->_cellPadding===null?-1:$this->_cellPadding;
+ }
+
+ /**
+ * @param integer cellpadding of the table. A value equal to -1 clears up the setting.
+ * @throws TInvalidDataValueException if the value is less than -1.
+ */
+ public function setCellPadding($value)
+ {
+ if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellpadding_invalid');
+ }
+
+ /**
+ * @return integer cellspacing of the table. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ return $this->_cellSpacing===null?-1:$this->_cellSpacing;
+ }
+
+ /**
+ * @param integer cellspacing of the table. A value equal to -1 clears up the setting.
+ * @throws TInvalidDataValueException if the value is less than -1.
+ */
+ public function setCellSpacing($value)
+ {
+ if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1)
+ throw new TInvalidDataValueException('tablestyle_cellspacing_invalid');
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines;
+ }
+
+ /**
+ * Sets the grid line style of the table.
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines');
+ }
+
+
+ /**
+ * @return boolean whether the table borders should be collapsed. Defaults to false.
+ */
+ public function getBorderCollapse()
+ {
+ return $this->_borderCollapse===null?false:$this->_borderCollapse;
+ }
+
+ /**
+ * @param boolean whether the table borders should be collapsed.
+ */
+ public function setBorderCollapse($value)
+ {
+ $this->_borderCollapse=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * TTableItemStyle class.
+ * TTableItemStyle represents the CSS style specific for HTML table item.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableItemStyle extends TStyle
+{
+ /**
+ * @var THorizontalAlign horizontal alignment of the contents within the table item
+ */
+ private $_horizontalAlign=null;
+ /**
+ * @var TVerticalAlign vertical alignment of the contents within the table item
+ */
+ private $_verticalAlign=null;
+ /**
+ * @var boolean whether the content wraps within the table item
+ */
+ private $_wrap=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TTableItemStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_verticalAlign=null;
+ $this->_horizontalAlign=null;
+ $this->_wrap=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($this->_verticalAlign===null && $style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($this->_horizontalAlign===null && $style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($this->_wrap===null && $style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TTableItemStyle)
+ {
+ if($style->_verticalAlign!==null)
+ $this->_verticalAlign=$style->_verticalAlign;
+ if($style->_horizontalAlign!==null)
+ $this->_horizontalAlign=$style->_horizontalAlign;
+ if($style->_wrap!==null)
+ $this->_wrap=$style->_wrap;
+ }
+ }
+
+ /**
+ * Adds attributes related to CSS styles to renderer.
+ * This method overrides the parent implementation.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function addAttributesToRender($writer)
+ {
+ if(!$this->getWrap())
+ $writer->addStyleAttribute('white-space','nowrap');
+
+ if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet)
+ $writer->addAttribute('align',strtolower($horizontalAlign));
+
+ if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet)
+ $writer->addAttribute('valign',strtolower($verticalAlign));
+
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the contents within the table item, defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign;
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * @param THorizontalAlign the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign');
+ }
+
+ /**
+ * @return TVerticalAlign the vertical alignment of the contents within the table item, defaults to TVerticalAlign::NotSet.
+ */
+ public function getVerticalAlign()
+ {
+ return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign;
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * @param TVerticalAlign the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign');
+ }
+
+ /**
+ * @return boolean whether the content wraps within the table item. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->_wrap===null?true:$this->_wrap;
+ }
+
+ /**
+ * Sets the value indicating whether the content wraps within the table item.
+ * @param boolean whether the content wraps within the panel.
+ */
+ public function setWrap($value)
+ {
+ $this->_wrap=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * THorizontalAlign class.
+ * THorizontalAlign defines the enumerable type for the possible horizontal alignments in a CSS style.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the alignment is not specified.
+ * - Left: left aligned
+ * - Right: right aligned
+ * - Center: center aligned
+ * - Justify: the begin and end are justified
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class THorizontalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Left='Left';
+ const Right='Right';
+ const Center='Center';
+ const Justify='Justify';
+}
+
+/**
+ * TVerticalAlign class.
+ * TVerticalAlign defines the enumerable type for the possible vertical alignments in a CSS style.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the alignment is not specified.
+ * - Top: top aligned
+ * - Bottom: bottom aligned
+ * - Middle: middle aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TVerticalAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Top='Top';
+ const Bottom='Bottom';
+ const Middle='Middle';
+}
+
+
+/**
+ * TTableGridLines class.
+ * TTableGridLines defines the enumerable type for the possible grid line types of an HTML table.
+ *
+ * The following enumerable values are defined:
+ * - None: no grid lines
+ * - Horizontal: horizontal grid lines only
+ * - Vertical: vertical grid lines only
+ * - Both: both horizontal and vertical grid lines are shown
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableGridLines extends TEnumerable
+{
+ const None='None';
+ const Horizontal='Horizontal';
+ const Vertical='Vertical';
+ const Both='Both';
+}
+
diff --git a/framework/Web/UI/WebControls/TTable.php b/framework/Web/UI/WebControls/TTable.php
index a333bf09..b7a774ae 100644
--- a/framework/Web/UI/WebControls/TTable.php
+++ b/framework/Web/UI/WebControls/TTable.php
@@ -1,410 +1,410 @@
-<?php
-/**
- * TTable and TTableRowCollection class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTable and TTableRowCollection class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTable class
- *
- * TTable displays an HTML table on a Web page.
- *
- * A table may have {@link setCaption Caption}, whose alignment is specified
- * via {@link setCaptionAlign CaptionAlign}. The table cellpadding and cellspacing
- * are specified via {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
- * properties, respectively. The {@link setGridLines GridLines} specifies how
- * the table should display its borders. The horizontal alignment of the table
- * content can be specified via {@link setHorizontalAlign HorizontalAlign},
- * and {@link setBackImageUrl BackImageUrl} can assign a background image to the table.
- *
- * A TTable maintains a list of {@link TTableRow} controls in its
- * {@link getRows Rows} property. Each {@link TTableRow} represents
- * an HTML table row.
- *
- * To populate the table {@link getRows Rows}, you may either use control template
- * or dynamically create {@link TTableRow} in code.
- * In template, do as follows to create the table rows and cells,
- * <code>
- * <com:TTable>
- * <com:TTableRow>
- * <com:TTableCell Text="content" />
- * <com:TTableCell Text="content" />
- * </com:TTableRow>
- * <com:TTableRow>
- * <com:TTableCell Text="content" />
- * <com:TTableCell Text="content" />
- * </com:TTableRow>
- * </com:TTable>
- * </code>
- * The above can also be accomplished in code as follows,
- * <code>
- * $table=new TTable;
- * $row=new TTableRow;
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $table->Rows->add($row);
- * $row=new TTableRow;
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
- * $table->Rows->add($row);
- * </code>
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTable extends TWebControl
-{
- /**
- * @return string tag name for the table
- */
- protected function getTagName()
- {
- return 'table';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TTableRow} objects into the {@link getRows Rows} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TTableRow)
- $this->getRows()->add($object);
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableStyle} to be used by the table.
- * @return TTableStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableStyle;
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $border=0;
- if($this->getHasStyle())
- {
- if($this->getGridLines()!==TTableGridLines::None)
- {
- if(($border=$this->getBorderWidth())==='')
- $border=1;
- else
- $border=(int)$border;
- }
- }
- $writer->addAttribute('border',"$border");
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TTableRowCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return new TTableRowCollection($this);
- }
-
- /**
- * @return TTableRowCollection list of {@link TTableRow} controls
- */
- public function getRows()
- {
- return $this->getControls();
- }
-
- /**
- * @return string table caption
- */
- public function getCaption()
- {
- return $this->getViewState('Caption','');
- }
-
- /**
- * @param string table caption
- */
- public function setCaption($value)
- {
- $this->setViewState('Caption',$value,'');
- }
-
- /**
- * @return TTableCaptionAlign table caption alignment. Defaults to TTableCaptionAlign::NotSet.
- */
- public function getCaptionAlign()
- {
- return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
- }
-
- /**
- * @param TTableCaptionAlign table caption alignment.
- */
- public function setCaptionAlign($value)
- {
- $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
- }
-
- /**
- * @return integer the cellspacing for the table. Defaults to -1, meaning not set.
- */
- public function getCellSpacing()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellSpacing();
- else
- return -1;
- }
-
- /**
- * @param integer the cellspacing for the table. Defaults to -1, meaning not set.
- */
- public function setCellSpacing($value)
- {
- $this->getStyle()->setCellSpacing($value);
- }
-
- /**
- * @return integer the cellpadding for the table. Defaults to -1, meaning not set.
- */
- public function getCellPadding()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getCellPadding();
- else
- return -1;
- }
-
- /**
- * @param integer the cellpadding for the table. Defaults to -1, meaning not set.
- */
- public function setCellPadding($value)
- {
- $this->getStyle()->setCellPadding($value);
- }
-
- /**
- * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return THorizontalAlign::NotSet;
- }
-
- /**
- * @param THorizontalAlign the horizontal alignment of the table content.
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
- */
- public function getGridLines()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getGridLines();
- else
- return TTableGridLines::None;
- }
-
- /**
- * @param TTableGridLines the grid line setting of the table
- */
- public function setGridLines($value)
- {
- $this->getStyle()->setGridLines($value);
- }
-
- /**
- * @return string the URL of the background image for the table
- */
- public function getBackImageUrl()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getBackImageUrl();
- else
- return '';
- }
-
- /**
- * Sets the URL of the background image for the table
- * @param string the URL
- */
- public function setBackImageUrl($value)
- {
- $this->getStyle()->setBackImageUrl($value);
- }
-
- /**
- * Renders the openning tag for the table control which will render table caption if present.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if(($caption=$this->getCaption())!=='')
- {
- if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
- $writer->addAttribute('align',strtolower($align));
- $writer->renderBeginTag('caption');
- $writer->write($caption);
- $writer->renderEndTag();
- }
- }
-
- /**
- * Renders body contents of the table.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if($this->getHasControls())
- {
- $renderTableSection=false;
- foreach($this->getControls() as $row)
- {
- if($row->getTableSection()!==TTableRowSection::Body)
- {
- $renderTableSection=true;
- break;
- }
- }
- if($renderTableSection)
- {
- $currentSection=TTableRowSection::Header;
- $writer->writeLine();
- foreach($this->getControls() as $index=>$row)
- {
- if(($section=$row->getTableSection())===$currentSection)
- {
- if($index===0 && $currentSection===TTableRowSection::Header)
- $writer->renderBeginTag('thead');
- }
- else
- {
- if($currentSection===TTableRowSection::Header)
- {
- if($index>0)
- $writer->renderEndTag();
- if($section===TTableRowSection::Body)
- $writer->renderBeginTag('tbody');
- else
- $writer->renderBeginTag('tfoot');
- $currentSection=$section;
- }
- else if($currentSection===TTableRowSection::Body)
- {
- $writer->renderEndTag();
- if($section===TTableRowSection::Footer)
- $writer->renderBeginTag('tfoot');
- else
- throw new TConfigurationException('table_tablesection_outoforder');
- $currentSection=$section;
- }
- else // Footer
- throw new TConfigurationException('table_tablesection_outoforder');
- }
- $row->renderControl($writer);
- $writer->writeLine();
- }
- $writer->renderEndTag();
- }
- else
- {
- $writer->writeLine();
- foreach($this->getControls() as $row)
- {
- $row->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
- }
-}
-
-
-/**
- * TTableRowCollection class.
- *
- * TTableRowCollection is used to maintain a list of rows belong to a table.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableRowCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added table row.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TTableRow object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TTableRow)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tablerowcollection_tablerow_required');
- }
-}
-
-
-/**
- * TTableCaptionAlign class.
- * TTableCaptionAlign defines the enumerable type for the possible alignments
- * that a table caption can take.
- *
- * The following enumerable values are defined:
- * - NotSet: alignment not specified
- * - Top: top aligned
- * - Bottom: bottom aligned
- * - Left: left aligned
- * - Right: right aligned
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableCaptionAlign extends TEnumerable
-{
- const NotSet='NotSet';
- const Top='Top';
- const Bottom='Bottom';
- const Left='Left';
- const Right='Right';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTable class
+ *
+ * TTable displays an HTML table on a Web page.
+ *
+ * A table may have {@link setCaption Caption}, whose alignment is specified
+ * via {@link setCaptionAlign CaptionAlign}. The table cellpadding and cellspacing
+ * are specified via {@link setCellPadding CellPadding} and {@link setCellSpacing CellSpacing}
+ * properties, respectively. The {@link setGridLines GridLines} specifies how
+ * the table should display its borders. The horizontal alignment of the table
+ * content can be specified via {@link setHorizontalAlign HorizontalAlign},
+ * and {@link setBackImageUrl BackImageUrl} can assign a background image to the table.
+ *
+ * A TTable maintains a list of {@link TTableRow} controls in its
+ * {@link getRows Rows} property. Each {@link TTableRow} represents
+ * an HTML table row.
+ *
+ * To populate the table {@link getRows Rows}, you may either use control template
+ * or dynamically create {@link TTableRow} in code.
+ * In template, do as follows to create the table rows and cells,
+ * <code>
+ * <com:TTable>
+ * <com:TTableRow>
+ * <com:TTableCell Text="content" />
+ * <com:TTableCell Text="content" />
+ * </com:TTableRow>
+ * <com:TTableRow>
+ * <com:TTableCell Text="content" />
+ * <com:TTableCell Text="content" />
+ * </com:TTableRow>
+ * </com:TTable>
+ * </code>
+ * The above can also be accomplished in code as follows,
+ * <code>
+ * $table=new TTable;
+ * $row=new TTableRow;
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $table->Rows->add($row);
+ * $row=new TTableRow;
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $cell=new TTableCell; $cell->Text="content"; $row->Cells->add($cell);
+ * $table->Rows->add($row);
+ * </code>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTable extends TWebControl
+{
+ /**
+ * @return string tag name for the table
+ */
+ protected function getTagName()
+ {
+ return 'table';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TTableRow} objects into the {@link getRows Rows} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TTableRow)
+ $this->getRows()->add($object);
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableStyle} to be used by the table.
+ * @return TTableStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableStyle;
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ $border=0;
+ if($this->getHasStyle())
+ {
+ if($this->getGridLines()!==TTableGridLines::None)
+ {
+ if(($border=$this->getBorderWidth())==='')
+ $border=1;
+ else
+ $border=(int)$border;
+ }
+ }
+ $writer->addAttribute('border',"$border");
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TTableRowCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return new TTableRowCollection($this);
+ }
+
+ /**
+ * @return TTableRowCollection list of {@link TTableRow} controls
+ */
+ public function getRows()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * @return string table caption
+ */
+ public function getCaption()
+ {
+ return $this->getViewState('Caption','');
+ }
+
+ /**
+ * @param string table caption
+ */
+ public function setCaption($value)
+ {
+ $this->setViewState('Caption',$value,'');
+ }
+
+ /**
+ * @return TTableCaptionAlign table caption alignment. Defaults to TTableCaptionAlign::NotSet.
+ */
+ public function getCaptionAlign()
+ {
+ return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @param TTableCaptionAlign table caption alignment.
+ */
+ public function setCaptionAlign($value)
+ {
+ $this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
+ }
+
+ /**
+ * @return integer the cellspacing for the table. Defaults to -1, meaning not set.
+ */
+ public function getCellSpacing()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellSpacing();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellspacing for the table. Defaults to -1, meaning not set.
+ */
+ public function setCellSpacing($value)
+ {
+ $this->getStyle()->setCellSpacing($value);
+ }
+
+ /**
+ * @return integer the cellpadding for the table. Defaults to -1, meaning not set.
+ */
+ public function getCellPadding()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getCellPadding();
+ else
+ return -1;
+ }
+
+ /**
+ * @param integer the cellpadding for the table. Defaults to -1, meaning not set.
+ */
+ public function setCellPadding($value)
+ {
+ $this->getStyle()->setCellPadding($value);
+ }
+
+ /**
+ * @return THorizontalAlign the horizontal alignment of the table content. Defaults to THorizontalAlign::NotSet.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return THorizontalAlign::NotSet;
+ }
+
+ /**
+ * @param THorizontalAlign the horizontal alignment of the table content.
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return TTableGridLines the grid line setting of the table. Defaults to TTableGridLines::None.
+ */
+ public function getGridLines()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getGridLines();
+ else
+ return TTableGridLines::None;
+ }
+
+ /**
+ * @param TTableGridLines the grid line setting of the table
+ */
+ public function setGridLines($value)
+ {
+ $this->getStyle()->setGridLines($value);
+ }
+
+ /**
+ * @return string the URL of the background image for the table
+ */
+ public function getBackImageUrl()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getBackImageUrl();
+ else
+ return '';
+ }
+
+ /**
+ * Sets the URL of the background image for the table
+ * @param string the URL
+ */
+ public function setBackImageUrl($value)
+ {
+ $this->getStyle()->setBackImageUrl($value);
+ }
+
+ /**
+ * Renders the openning tag for the table control which will render table caption if present.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if(($caption=$this->getCaption())!=='')
+ {
+ if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
+ $writer->addAttribute('align',strtolower($align));
+ $writer->renderBeginTag('caption');
+ $writer->write($caption);
+ $writer->renderEndTag();
+ }
+ }
+
+ /**
+ * Renders body contents of the table.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if($this->getHasControls())
+ {
+ $renderTableSection=false;
+ foreach($this->getControls() as $row)
+ {
+ if($row->getTableSection()!==TTableRowSection::Body)
+ {
+ $renderTableSection=true;
+ break;
+ }
+ }
+ if($renderTableSection)
+ {
+ $currentSection=TTableRowSection::Header;
+ $writer->writeLine();
+ foreach($this->getControls() as $index=>$row)
+ {
+ if(($section=$row->getTableSection())===$currentSection)
+ {
+ if($index===0 && $currentSection===TTableRowSection::Header)
+ $writer->renderBeginTag('thead');
+ }
+ else
+ {
+ if($currentSection===TTableRowSection::Header)
+ {
+ if($index>0)
+ $writer->renderEndTag();
+ if($section===TTableRowSection::Body)
+ $writer->renderBeginTag('tbody');
+ else
+ $writer->renderBeginTag('tfoot');
+ $currentSection=$section;
+ }
+ else if($currentSection===TTableRowSection::Body)
+ {
+ $writer->renderEndTag();
+ if($section===TTableRowSection::Footer)
+ $writer->renderBeginTag('tfoot');
+ else
+ throw new TConfigurationException('table_tablesection_outoforder');
+ $currentSection=$section;
+ }
+ else // Footer
+ throw new TConfigurationException('table_tablesection_outoforder');
+ }
+ $row->renderControl($writer);
+ $writer->writeLine();
+ }
+ $writer->renderEndTag();
+ }
+ else
+ {
+ $writer->writeLine();
+ foreach($this->getControls() as $row)
+ {
+ $row->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ * TTableRowCollection class.
+ *
+ * TTableRowCollection is used to maintain a list of rows belong to a table.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableRowCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added table row.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TTableRow object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TTableRow)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tablerowcollection_tablerow_required');
+ }
+}
+
+
+/**
+ * TTableCaptionAlign class.
+ * TTableCaptionAlign defines the enumerable type for the possible alignments
+ * that a table caption can take.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: alignment not specified
+ * - Top: top aligned
+ * - Bottom: bottom aligned
+ * - Left: left aligned
+ * - Right: right aligned
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableCaptionAlign extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Top='Top';
+ const Bottom='Bottom';
+ const Left='Left';
+ const Right='Right';
+}
+
diff --git a/framework/Web/UI/WebControls/TTableCell.php b/framework/Web/UI/WebControls/TTableCell.php
index 6b43990b..70ff573f 100644
--- a/framework/Web/UI/WebControls/TTableCell.php
+++ b/framework/Web/UI/WebControls/TTableCell.php
@@ -1,222 +1,222 @@
-<?php
-/**
- * TTableCell class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTableCell class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTableCell class.
- *
- * TTableCell displays a table cell on a Web page. Content of the table cell
- * is specified by the {@link setText Text} property. If {@link setText Text}
- * is empty, the body contents enclosed by the table cell component tag are rendered.
- * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure
- * it does not contain dangerous characters.
- *
- * The horizontal and vertical alignments of the contents in the cell
- * are specified via {@link setHorizontalAlign HorizontalAlign} and
- * {@link setVerticalAlign VerticalAlign} properties, respectively.
- *
- * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan}
- * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property
- * indicates whether the contents in the cell should be wrapped.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableCell extends TWebControl implements IDataRenderer
-{
- /**
- * @return string tag name for the table cell
- */
- protected function getTagName()
- {
- return 'td';
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by the table cell.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getVerticalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getVerticalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * Valid values include 'NotSet','Top','Bottom','Middle'
- * @param string the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->getStyle()->setVerticalAlign($value);
- }
-
- /**
- * @return integer the columnspan for the table cell, 0 if not set.
- */
- public function getColumnSpan()
- {
- return $this->getViewState('ColumnSpan', 0);
- }
-
- /**
- * Sets the columnspan for the table cell.
- * @param integer the columnspan for the table cell, 0 if not set.
- */
- public function setColumnSpan($value)
- {
- $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0);
- }
-
- /**
- * @return integer the rowspan for the table cell, 0 if not set.
- */
- public function getRowSpan()
- {
- return $this->getViewState('RowSpan', 0);
- }
-
- /**
- * Sets the rowspan for the table cell.
- * @param integer the rowspan for the table cell, 0 if not set.
- */
- public function setRowSpan($value)
- {
- $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0);
- }
-
- /**
- * @return boolean whether the text content wraps within a table cell. Defaults to true.
- */
- public function getWrap()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getWrap();
- else
- return true;
- }
-
- /**
- * Sets the value indicating whether the text content wraps within a table cell.
- * @param boolean whether the text content wraps within a table cell.
- */
- public function setWrap($value)
- {
- $this->getStyle()->setWrap($value);
- }
-
- /**
- * @return string the text content of the table cell.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content of the table cell.
- * If the text content is empty, body content (child controls) of the cell will be rendered.
- * @param string the text content
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- }
-
- /**
- * Returns the text content of the table cell.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text content of the table cell.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text content of the table cell.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text content of the table cell.
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($colspan=$this->getColumnSpan())>0)
- $writer->addAttribute('colspan',"$colspan");
- if(($rowspan=$this->getRowSpan())>0)
- $writer->addAttribute('rowspan',"$rowspan");
- }
-
- /**
- * Renders body contents of the table cell.
- * @param THtmlWriter the writer used for the rendering purpose.
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())!=='')
- $writer->write($text);
- else if($this->getHasControls())
- parent::renderContents($writer);
- else
- $writer->write('&nbsp;');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTableCell class.
+ *
+ * TTableCell displays a table cell on a Web page. Content of the table cell
+ * is specified by the {@link setText Text} property. If {@link setText Text}
+ * is empty, the body contents enclosed by the table cell component tag are rendered.
+ * Note, {@link setText Text} is not HTML-encoded when displayed. So make sure
+ * it does not contain dangerous characters.
+ *
+ * The horizontal and vertical alignments of the contents in the cell
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * The colspan and rowspan of the cell are specified via {@link setColumnSpan ColumnSpan}
+ * and {@link setRowSpan RowSpan} properties. And the {@link setWrap Wrap} property
+ * indicates whether the contents in the cell should be wrapped.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableCell extends TWebControl implements IDataRenderer
+{
+ /**
+ * @return string tag name for the table cell
+ */
+ protected function getTagName()
+ {
+ return 'td';
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by the table cell.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getVerticalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getVerticalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * Valid values include 'NotSet','Top','Bottom','Middle'
+ * @param string the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->getStyle()->setVerticalAlign($value);
+ }
+
+ /**
+ * @return integer the columnspan for the table cell, 0 if not set.
+ */
+ public function getColumnSpan()
+ {
+ return $this->getViewState('ColumnSpan', 0);
+ }
+
+ /**
+ * Sets the columnspan for the table cell.
+ * @param integer the columnspan for the table cell, 0 if not set.
+ */
+ public function setColumnSpan($value)
+ {
+ $this->setViewState('ColumnSpan', TPropertyValue::ensureInteger($value), 0);
+ }
+
+ /**
+ * @return integer the rowspan for the table cell, 0 if not set.
+ */
+ public function getRowSpan()
+ {
+ return $this->getViewState('RowSpan', 0);
+ }
+
+ /**
+ * Sets the rowspan for the table cell.
+ * @param integer the rowspan for the table cell, 0 if not set.
+ */
+ public function setRowSpan($value)
+ {
+ $this->setViewState('RowSpan', TPropertyValue::ensureInteger($value), 0);
+ }
+
+ /**
+ * @return boolean whether the text content wraps within a table cell. Defaults to true.
+ */
+ public function getWrap()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getWrap();
+ else
+ return true;
+ }
+
+ /**
+ * Sets the value indicating whether the text content wraps within a table cell.
+ * @param boolean whether the text content wraps within a table cell.
+ */
+ public function setWrap($value)
+ {
+ $this->getStyle()->setWrap($value);
+ }
+
+ /**
+ * @return string the text content of the table cell.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content of the table cell.
+ * If the text content is empty, body content (child controls) of the cell will be rendered.
+ * @param string the text content
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ }
+
+ /**
+ * Returns the text content of the table cell.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text content of the table cell.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text content of the table cell.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text content of the table cell.
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($colspan=$this->getColumnSpan())>0)
+ $writer->addAttribute('colspan',"$colspan");
+ if(($rowspan=$this->getRowSpan())>0)
+ $writer->addAttribute('rowspan',"$rowspan");
+ }
+
+ /**
+ * Renders body contents of the table cell.
+ * @param THtmlWriter the writer used for the rendering purpose.
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())!=='')
+ $writer->write($text);
+ else if($this->getHasControls())
+ parent::renderContents($writer);
+ else
+ $writer->write('&nbsp;');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TTableFooterRow.php b/framework/Web/UI/WebControls/TTableFooterRow.php
index 84bc29f1..1387c385 100644
--- a/framework/Web/UI/WebControls/TTableFooterRow.php
+++ b/framework/Web/UI/WebControls/TTableFooterRow.php
@@ -1,47 +1,47 @@
-<?php
-/**
- * TTableFooterRow class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTableFooterRow class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class.
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTableFooterRow class.
- *
- * TTableFooterRow displays a table footer row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TTableFooterRow extends TTableRow
-{
- /**
- * @return string location of a row in a table. Always returns 'Footer'.
- */
- public function getTableSection()
- {
- return 'Footer';
- }
-
- /**
- * @param string location of a row in a table.
- * @throws TInvalidOperationException if this method is invoked
- */
- public function setTableSection($value)
- {
- throw new TInvalidOperationException('tablefooterrow_tablesection_readonly');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class.
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTableFooterRow class.
+ *
+ * TTableFooterRow displays a table footer row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TTableFooterRow extends TTableRow
+{
+ /**
+ * @return string location of a row in a table. Always returns 'Footer'.
+ */
+ public function getTableSection()
+ {
+ return 'Footer';
+ }
+
+ /**
+ * @param string location of a row in a table.
+ * @throws TInvalidOperationException if this method is invoked
+ */
+ public function setTableSection($value)
+ {
+ throw new TInvalidOperationException('tablefooterrow_tablesection_readonly');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TTableHeaderCell.php b/framework/Web/UI/WebControls/TTableHeaderCell.php
index bbf3e58a..72eae44e 100644
--- a/framework/Web/UI/WebControls/TTableHeaderCell.php
+++ b/framework/Web/UI/WebControls/TTableHeaderCell.php
@@ -1,124 +1,124 @@
-<?php
-/**
- * TTableHeaderCell class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTableHeaderCell class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableCell class
- */
-Prado::using('System.Web.UI.WebControls.TTableCell');
-
-
-/**
- * TTableHeaderCell class.
- *
- * TTableHeaderCell displays a table header cell on a Web page.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableHeaderCell extends TTableCell
-{
- /**
- * @return string tag name for the table header cell
- */
- protected function getTagName()
- {
- return 'th';
- }
-
- /**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- */
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- if(($scope=$this->getScope())!==TTableHeaderScope::NotSet)
- $writer->addAttribute('scope',$scope===TTableHeaderScope::Row?'row':'col');
- if(($text=$this->getAbbreviatedText())!=='')
- $writer->addAttribute('abbr',$text);
- if(($text=$this->getCategoryText())!=='')
- $writer->addAttribute('axis',$text);
- }
-
- /**
- * @return TTableHeaderScope the scope of the cells that the header cell applies to. Defaults to TTableHeaderScope::NotSet.
- */
- public function getScope()
- {
- return $this->getViewState('Scope',TTableHeaderScope::NotSet);
- }
-
- /**
- * @param TTableHeaderScope the scope of the cells that the header cell applies to.
- */
- public function setScope($value)
- {
- $this->setViewState('Scope',TPropertyValue::ensureEnum($value,'TTableHeaderScope'),TTableHeaderScope::NotSet);
- }
-
- /**
- * @return string the abbr attribute of the HTML th element
- */
- public function getAbbreviatedText()
- {
- return $this->getViewState('AbbreviatedText','');
- }
-
- /**
- * @param string the abbr attribute of the HTML th element
- */
- public function setAbbreviatedText($value)
- {
- $this->setViewState('AbbreviatedText',$value,'');
- }
-
- /**
- * @return string the axis attribute of the HTML th element
- */
- public function getCategoryText()
- {
- return $this->getViewState('CategoryText','');
- }
-
- /**
- * @param string the axis attribute of the HTML th element
- */
- public function setCategoryText($value)
- {
- $this->setViewState('CategoryText',$value,'');
- }
-}
-
-
-/**
- * TTableHeaderScope class.
- * TTableHeaderScope defines the enumerable type for the possible table scopes that a table header is associated with.
- *
- * The following enumerable values are defined:
- * - NotSet: the scope is not specified
- * - Row: the scope is row-wise
- * - Column: the scope is column-wise
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableHeaderScope extends TEnumerable
-{
- const NotSet='NotSet';
- const Row='Row';
- const Column='Column';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableCell class
+ */
+Prado::using('System.Web.UI.WebControls.TTableCell');
+
+
+/**
+ * TTableHeaderCell class.
+ *
+ * TTableHeaderCell displays a table header cell on a Web page.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableHeaderCell extends TTableCell
+{
+ /**
+ * @return string tag name for the table header cell
+ */
+ protected function getTagName()
+ {
+ return 'th';
+ }
+
+ /**
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ */
+ protected function addAttributesToRender($writer)
+ {
+ parent::addAttributesToRender($writer);
+ if(($scope=$this->getScope())!==TTableHeaderScope::NotSet)
+ $writer->addAttribute('scope',$scope===TTableHeaderScope::Row?'row':'col');
+ if(($text=$this->getAbbreviatedText())!=='')
+ $writer->addAttribute('abbr',$text);
+ if(($text=$this->getCategoryText())!=='')
+ $writer->addAttribute('axis',$text);
+ }
+
+ /**
+ * @return TTableHeaderScope the scope of the cells that the header cell applies to. Defaults to TTableHeaderScope::NotSet.
+ */
+ public function getScope()
+ {
+ return $this->getViewState('Scope',TTableHeaderScope::NotSet);
+ }
+
+ /**
+ * @param TTableHeaderScope the scope of the cells that the header cell applies to.
+ */
+ public function setScope($value)
+ {
+ $this->setViewState('Scope',TPropertyValue::ensureEnum($value,'TTableHeaderScope'),TTableHeaderScope::NotSet);
+ }
+
+ /**
+ * @return string the abbr attribute of the HTML th element
+ */
+ public function getAbbreviatedText()
+ {
+ return $this->getViewState('AbbreviatedText','');
+ }
+
+ /**
+ * @param string the abbr attribute of the HTML th element
+ */
+ public function setAbbreviatedText($value)
+ {
+ $this->setViewState('AbbreviatedText',$value,'');
+ }
+
+ /**
+ * @return string the axis attribute of the HTML th element
+ */
+ public function getCategoryText()
+ {
+ return $this->getViewState('CategoryText','');
+ }
+
+ /**
+ * @param string the axis attribute of the HTML th element
+ */
+ public function setCategoryText($value)
+ {
+ $this->setViewState('CategoryText',$value,'');
+ }
+}
+
+
+/**
+ * TTableHeaderScope class.
+ * TTableHeaderScope defines the enumerable type for the possible table scopes that a table header is associated with.
+ *
+ * The following enumerable values are defined:
+ * - NotSet: the scope is not specified
+ * - Row: the scope is row-wise
+ * - Column: the scope is column-wise
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableHeaderScope extends TEnumerable
+{
+ const NotSet='NotSet';
+ const Row='Row';
+ const Column='Column';
+}
+
diff --git a/framework/Web/UI/WebControls/TTableHeaderRow.php b/framework/Web/UI/WebControls/TTableHeaderRow.php
index 448902dc..2c05b94d 100644
--- a/framework/Web/UI/WebControls/TTableHeaderRow.php
+++ b/framework/Web/UI/WebControls/TTableHeaderRow.php
@@ -1,47 +1,47 @@
-<?php
-/**
- * TTableHeaderRow class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTableHeaderRow class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableRow class.
- */
-Prado::using('System.Web.UI.WebControls.TTableRow');
-
-/**
- * TTableHeaderRow class.
- *
- * TTableHeaderRow displays a table header row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.1
- */
-class TTableHeaderRow extends TTableRow
-{
- /**
- * @return string location of a row in a table. Always returns 'Header'.
- */
- public function getTableSection()
- {
- return 'Header';
- }
-
- /**
- * @param string location of a row in a table.
- * @throws TInvalidOperationException if this method is invoked
- */
- public function setTableSection($value)
- {
- throw new TInvalidOperationException('tableheaderrow_tablesection_readonly');
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableRow class.
+ */
+Prado::using('System.Web.UI.WebControls.TTableRow');
+
+/**
+ * TTableHeaderRow class.
+ *
+ * TTableHeaderRow displays a table header row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.1
+ */
+class TTableHeaderRow extends TTableRow
+{
+ /**
+ * @return string location of a row in a table. Always returns 'Header'.
+ */
+ public function getTableSection()
+ {
+ return 'Header';
+ }
+
+ /**
+ * @param string location of a row in a table.
+ * @throws TInvalidOperationException if this method is invoked
+ */
+ public function setTableSection($value)
+ {
+ throw new TInvalidOperationException('tableheaderrow_tablesection_readonly');
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TTableRow.php b/framework/Web/UI/WebControls/TTableRow.php
index e50099bf..3cfc82d0 100644
--- a/framework/Web/UI/WebControls/TTableRow.php
+++ b/framework/Web/UI/WebControls/TTableRow.php
@@ -1,208 +1,208 @@
-<?php
-/**
- * TTableRow and TTableCellCollection class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTableRow and TTableCellCollection class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TTableCell class
- */
-Prado::using('System.Web.UI.WebControls.TTableCell');
-
-/**
- * TTableRow class.
- *
- * TTableRow displays a table row. The table cells in the row can be accessed
- * via {@link getCells Cells}. The horizontal and vertical alignments of the row
- * are specified via {@link setHorizontalAlign HorizontalAlign} and
- * {@link setVerticalAlign VerticalAlign} properties, respectively.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableRow extends TWebControl
-{
- /**
- * @return string tag name for the table
- */
- protected function getTagName()
- {
- return 'tr';
- }
-
- /**
- * Adds object parsed from template to the control.
- * This method adds only {@link TTableCell} objects into the {@link getCells Cells} collection.
- * All other objects are ignored.
- * @param mixed object parsed from template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TTableCell)
- $this->getCells()->add($object);
- }
-
- /**
- * Creates a style object for the control.
- * This method creates a {@link TTableItemStyle} to be used by the table row.
- * @return TStyle control style to be used
- */
- protected function createStyle()
- {
- return new TTableItemStyle;
- }
-
- /**
- * Creates a control collection object that is to be used to hold child controls
- * @return TTableCellCollection control collection
- * @see getControls
- */
- protected function createControlCollection()
- {
- return new TTableCellCollection($this);
- }
-
- /**
- * @return TTableCellCollection list of {@link TTableCell} controls
- */
- public function getCells()
- {
- return $this->getControls();
- }
-
- /**
- * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getHorizontalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getHorizontalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the horizontal alignment of the contents within the table item.
- * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
- * @param string the horizontal alignment
- */
- public function setHorizontalAlign($value)
- {
- $this->getStyle()->setHorizontalAlign($value);
- }
-
- /**
- * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
- */
- public function getVerticalAlign()
- {
- if($this->getHasStyle())
- return $this->getStyle()->getVerticalAlign();
- else
- return 'NotSet';
- }
-
- /**
- * Sets the vertical alignment of the contents within the table item.
- * Valid values include 'NotSet','Top','Bottom','Middle'
- * @param string the horizontal alignment
- */
- public function setVerticalAlign($value)
- {
- $this->getStyle()->setVerticalAlign($value);
- }
-
- /**
- * @return TTableRowSection location of a row in a table. Defaults to TTableRowSection::Body.
- */
- public function getTableSection()
- {
- return $this->getViewState('TableSection',TTableRowSection::Body);
- }
-
- /**
- * @param TTableRowSection location of a row in a table.
- */
- public function setTableSection($value)
- {
- $this->setViewState('TableSection',TPropertyValue::ensureEnum($value,'TTableRowSection'),TTableRowSection::Body);
- }
-
- /**
- * Renders body contents of the table row
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderContents($writer)
- {
- if($this->getHasControls())
- {
- $writer->writeLine();
- foreach($this->getControls() as $cell)
- {
- $cell->renderControl($writer);
- $writer->writeLine();
- }
- }
- }
-}
-
-/**
- * TTableCellCollection class.
- *
- * TTableCellCollection is used to maintain a list of cells belong to a table row.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTableCellCollection extends TControlCollection
-{
- /**
- * Inserts an item at the specified position.
- * This overrides the parent implementation by performing additional
- * operations for each newly added table cell.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item to be inserted is not a TTableCell object.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TTableCell)
- parent::insertAt($index,$item);
- else
- throw new TInvalidDataTypeException('tablecellcollection_tablecell_required');
- }
-}
-
-
-/**
- * TTableRowSection class.
- * TTableRowSection defines the enumerable type for the possible table sections
- * that a {@link TTableRow} can be within.
- *
- * The following enumerable values are defined:
- * - Header: in table header
- * - Body: in table body
- * - Footer: in table footer
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTableRowSection extends TEnumerable
-{
- const Header='Header';
- const Body='Body';
- const Footer='Footer';
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TTableCell class
+ */
+Prado::using('System.Web.UI.WebControls.TTableCell');
+
+/**
+ * TTableRow class.
+ *
+ * TTableRow displays a table row. The table cells in the row can be accessed
+ * via {@link getCells Cells}. The horizontal and vertical alignments of the row
+ * are specified via {@link setHorizontalAlign HorizontalAlign} and
+ * {@link setVerticalAlign VerticalAlign} properties, respectively.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableRow extends TWebControl
+{
+ /**
+ * @return string tag name for the table
+ */
+ protected function getTagName()
+ {
+ return 'tr';
+ }
+
+ /**
+ * Adds object parsed from template to the control.
+ * This method adds only {@link TTableCell} objects into the {@link getCells Cells} collection.
+ * All other objects are ignored.
+ * @param mixed object parsed from template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TTableCell)
+ $this->getCells()->add($object);
+ }
+
+ /**
+ * Creates a style object for the control.
+ * This method creates a {@link TTableItemStyle} to be used by the table row.
+ * @return TStyle control style to be used
+ */
+ protected function createStyle()
+ {
+ return new TTableItemStyle;
+ }
+
+ /**
+ * Creates a control collection object that is to be used to hold child controls
+ * @return TTableCellCollection control collection
+ * @see getControls
+ */
+ protected function createControlCollection()
+ {
+ return new TTableCellCollection($this);
+ }
+
+ /**
+ * @return TTableCellCollection list of {@link TTableCell} controls
+ */
+ public function getCells()
+ {
+ return $this->getControls();
+ }
+
+ /**
+ * @return string the horizontal alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getHorizontalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getHorizontalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the horizontal alignment of the contents within the table item.
+ * Valid values include 'NotSet', 'Justify', 'Left', 'Right', 'Center'
+ * @param string the horizontal alignment
+ */
+ public function setHorizontalAlign($value)
+ {
+ $this->getStyle()->setHorizontalAlign($value);
+ }
+
+ /**
+ * @return string the vertical alignment of the contents within the table item, defaults to 'NotSet'.
+ */
+ public function getVerticalAlign()
+ {
+ if($this->getHasStyle())
+ return $this->getStyle()->getVerticalAlign();
+ else
+ return 'NotSet';
+ }
+
+ /**
+ * Sets the vertical alignment of the contents within the table item.
+ * Valid values include 'NotSet','Top','Bottom','Middle'
+ * @param string the horizontal alignment
+ */
+ public function setVerticalAlign($value)
+ {
+ $this->getStyle()->setVerticalAlign($value);
+ }
+
+ /**
+ * @return TTableRowSection location of a row in a table. Defaults to TTableRowSection::Body.
+ */
+ public function getTableSection()
+ {
+ return $this->getViewState('TableSection',TTableRowSection::Body);
+ }
+
+ /**
+ * @param TTableRowSection location of a row in a table.
+ */
+ public function setTableSection($value)
+ {
+ $this->setViewState('TableSection',TPropertyValue::ensureEnum($value,'TTableRowSection'),TTableRowSection::Body);
+ }
+
+ /**
+ * Renders body contents of the table row
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ if($this->getHasControls())
+ {
+ $writer->writeLine();
+ foreach($this->getControls() as $cell)
+ {
+ $cell->renderControl($writer);
+ $writer->writeLine();
+ }
+ }
+ }
+}
+
+/**
+ * TTableCellCollection class.
+ *
+ * TTableCellCollection is used to maintain a list of cells belong to a table row.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTableCellCollection extends TControlCollection
+{
+ /**
+ * Inserts an item at the specified position.
+ * This overrides the parent implementation by performing additional
+ * operations for each newly added table cell.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item to be inserted is not a TTableCell object.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TTableCell)
+ parent::insertAt($index,$item);
+ else
+ throw new TInvalidDataTypeException('tablecellcollection_tablecell_required');
+ }
+}
+
+
+/**
+ * TTableRowSection class.
+ * TTableRowSection defines the enumerable type for the possible table sections
+ * that a {@link TTableRow} can be within.
+ *
+ * The following enumerable values are defined:
+ * - Header: in table header
+ * - Body: in table body
+ * - Footer: in table footer
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTableRowSection extends TEnumerable
+{
+ const Header='Header';
+ const Body='Body';
+ const Footer='Footer';
+}
+
diff --git a/framework/Web/UI/WebControls/TTemplateColumn.php b/framework/Web/UI/WebControls/TTemplateColumn.php
index f2bf02d7..34c9bbaf 100644
--- a/framework/Web/UI/WebControls/TTemplateColumn.php
+++ b/framework/Web/UI/WebControls/TTemplateColumn.php
@@ -1,256 +1,256 @@
-<?php
-/**
- * TTemplateColumn class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTemplateColumn class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TDataGridColumn class file
- */
-Prado::using('System.Web.UI.WebControls.TDataGridColumn');
-
-/**
- * TTemplateColumn class
- *
- * TTemplateColumn customizes the layout of controls in the column with templates.
- * In particular, you can specify {@link setItemTemplate ItemTemplate},
- * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate}
- * and {@link setFooterTemplate FooterTemplate} to customize specific
- * type of cells in the column.
- *
- * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
- * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
- * the layout of the datagrid cells in browsing and editing mode.
- * A renderer refers to a control class that is to be instantiated as a control.
- * For more details, see {@link TRepeater} and {@link TDataList}.
- *
- * When a renderer and a template are both defined for a type of item, the former
- * takes precedence.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTemplateColumn extends TDataGridColumn
-{
- /**
- * Various item templates
- * @var string
- */
- private $_itemTemplate=null;
- private $_editItemTemplate=null;
- private $_headerTemplate=null;
- private $_footerTemplate=null;
-
- /**
- * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getItemRenderer()
- {
- return $this->getViewState('ItemRenderer','');
- }
-
- /**
- * Sets the item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the row of the data associated with the datagrid item that this cell resides in.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setItemRenderer($value)
- {
- $this->setViewState('ItemRenderer',$value,'');
- }
-
- /**
- * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
- * @since 3.1.0
- */
- public function getEditItemRenderer()
- {
- return $this->getViewState('EditItemRenderer','');
- }
-
- /**
- * Sets the edit item cell renderer class.
- *
- * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
- *
- * If the class implements {@link IDataRenderer}, the <b>Data</b> property
- * will be set as the row of the data associated with the datagrid item that this cell resides in.
- *
- * @param string the renderer class name in namespace format.
- * @since 3.1.0
- */
- public function setEditItemRenderer($value)
- {
- $this->setViewState('EditItemRenderer',$value,'');
- }
-
- /**
- * @return ITemplate the edit item template
- */
- public function getEditItemTemplate()
- {
- return $this->_editItemTemplate;
- }
-
- /**
- * @param ITemplate the edit item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setEditItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_editItemTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate');
- }
-
- /**
- * @return ITemplate the item template
- */
- public function getItemTemplate()
- {
- return $this->_itemTemplate;
- }
-
- /**
- * @param ITemplate the item template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setItemTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_itemTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate');
- }
-
- /**
- * @return ITemplate the header template
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate the header template.
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setHeaderTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_headerTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate');
- }
-
- /**
- * @return ITemplate the footer template
- */
- public function getFooterTemplate()
- {
- return $this->_footerTemplate;
- }
-
- /**
- * @param ITemplate the footer template
- * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
- */
- public function setFooterTemplate($value)
- {
- if($value instanceof ITemplate || $value===null)
- $this->_footerTemplate=$value;
- else
- throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate');
- }
-
- /**
- * Initializes the specified cell to its initial values.
- * This method overrides the parent implementation.
- * It initializes the cell based on different templates
- * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate).
- * @param TTableCell the cell to be initialized.
- * @param integer the index to the Columns property that the cell resides in.
- * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
- */
- public function initializeCell($cell,$columnIndex,$itemType)
- {
- if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
- {
- if($itemType===TListItemType::EditItem)
- {
- if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null)
- {
- $classPath=$this->getItemRenderer();
- $template=$this->_itemTemplate;
- }
- }
- else
- {
- $template=$this->_itemTemplate;
- $classPath=$this->getItemRenderer();
- }
- if($classPath!=='')
- {
- $control=Prado::createComponent($classPath);
- $cell->getControls()->add($control);
- if($control instanceof IItemDataRenderer)
- {
- $control->setItemIndex($cell->getParent()->getItemIndex());
- $control->setItemType($itemType);
- }
- if($control instanceof IDataRenderer)
- $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
- }
- else if($template!==null)
- $template->instantiateIn($cell);
- else if($itemType!==TListItemType::EditItem)
- $cell->setText('&nbsp;');
- }
- else if($itemType===TListItemType::Header)
- {
- if(($classPath=$this->getHeaderRenderer())!=='')
- $this->initializeHeaderCell($cell,$columnIndex);
- else if($this->_headerTemplate!==null)
- $this->_headerTemplate->instantiateIn($cell);
- else
- $this->initializeHeaderCell($cell,$columnIndex);
- }
- else if($itemType===TListItemType::Footer)
- {
- if(($classPath=$this->getFooterRenderer())!=='')
- $this->initializeFooterCell($cell,$columnIndex);
- else if($this->_footerTemplate!==null)
- $this->_footerTemplate->instantiateIn($cell);
- else
- $this->initializeFooterCell($cell,$columnIndex);
- }
- }
-
- /**
- * Databinds a cell in the column.
- * This method is invoked when datagrid performs databinding.
- * It populates the content of the cell with the relevant data from data source.
- */
- public function dataBindColumn($sender,$param)
- {
- $item=$sender->getNamingContainer();
- $sender->setData($item->getData());
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TDataGridColumn class file
+ */
+Prado::using('System.Web.UI.WebControls.TDataGridColumn');
+
+/**
+ * TTemplateColumn class
+ *
+ * TTemplateColumn customizes the layout of controls in the column with templates.
+ * In particular, you can specify {@link setItemTemplate ItemTemplate},
+ * {@link setEditItemTemplate EditItemTemplate}, {@link setHeaderTemplate HeaderTemplate}
+ * and {@link setFooterTemplate FooterTemplate} to customize specific
+ * type of cells in the column.
+ *
+ * Since v3.1.0, TTemplateColumn has introduced two new properties {@link setItemRenderer ItemRenderer}
+ * and {@link setEditItemRenderer EditItemRenderer} which can be used to specify
+ * the layout of the datagrid cells in browsing and editing mode.
+ * A renderer refers to a control class that is to be instantiated as a control.
+ * For more details, see {@link TRepeater} and {@link TDataList}.
+ *
+ * When a renderer and a template are both defined for a type of item, the former
+ * takes precedence.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTemplateColumn extends TDataGridColumn
+{
+ /**
+ * Various item templates
+ * @var string
+ */
+ private $_itemTemplate=null;
+ private $_editItemTemplate=null;
+ private $_headerTemplate=null;
+ private $_footerTemplate=null;
+
+ /**
+ * @return string the class name for the item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getItemRenderer()
+ {
+ return $this->getViewState('ItemRenderer','');
+ }
+
+ /**
+ * Sets the item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cells of the column.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the row of the data associated with the datagrid item that this cell resides in.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setItemRenderer($value)
+ {
+ $this->setViewState('ItemRenderer',$value,'');
+ }
+
+ /**
+ * @return string the class name for the edit item cell renderer. Defaults to empty, meaning not set.
+ * @since 3.1.0
+ */
+ public function getEditItemRenderer()
+ {
+ return $this->getViewState('EditItemRenderer','');
+ }
+
+ /**
+ * Sets the edit item cell renderer class.
+ *
+ * If not empty, the class will be used to instantiate as a child control in the item cell that is in edit mode.
+ *
+ * If the class implements {@link IDataRenderer}, the <b>Data</b> property
+ * will be set as the row of the data associated with the datagrid item that this cell resides in.
+ *
+ * @param string the renderer class name in namespace format.
+ * @since 3.1.0
+ */
+ public function setEditItemRenderer($value)
+ {
+ $this->setViewState('EditItemRenderer',$value,'');
+ }
+
+ /**
+ * @return ITemplate the edit item template
+ */
+ public function getEditItemTemplate()
+ {
+ return $this->_editItemTemplate;
+ }
+
+ /**
+ * @param ITemplate the edit item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setEditItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_editItemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','EditItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the item template
+ */
+ public function getItemTemplate()
+ {
+ return $this->_itemTemplate;
+ }
+
+ /**
+ * @param ITemplate the item template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setItemTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_itemTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','ItemTemplate');
+ }
+
+ /**
+ * @return ITemplate the header template
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate the header template.
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setHeaderTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_headerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','HeaderTemplate');
+ }
+
+ /**
+ * @return ITemplate the footer template
+ */
+ public function getFooterTemplate()
+ {
+ return $this->_footerTemplate;
+ }
+
+ /**
+ * @param ITemplate the footer template
+ * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
+ */
+ public function setFooterTemplate($value)
+ {
+ if($value instanceof ITemplate || $value===null)
+ $this->_footerTemplate=$value;
+ else
+ throw new TInvalidDataTypeException('templatecolumn_template_required','FooterTemplate');
+ }
+
+ /**
+ * Initializes the specified cell to its initial values.
+ * This method overrides the parent implementation.
+ * It initializes the cell based on different templates
+ * (ItemTemplate, EditItemTemplate, HeaderTemplate, FooterTemplate).
+ * @param TTableCell the cell to be initialized.
+ * @param integer the index to the Columns property that the cell resides in.
+ * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
+ */
+ public function initializeCell($cell,$columnIndex,$itemType)
+ {
+ if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem || $itemType===TListItemType::EditItem)
+ {
+ if($itemType===TListItemType::EditItem)
+ {
+ if(($classPath=$this->getEditItemRenderer())==='' && ($template=$this->_editItemTemplate)===null)
+ {
+ $classPath=$this->getItemRenderer();
+ $template=$this->_itemTemplate;
+ }
+ }
+ else
+ {
+ $template=$this->_itemTemplate;
+ $classPath=$this->getItemRenderer();
+ }
+ if($classPath!=='')
+ {
+ $control=Prado::createComponent($classPath);
+ $cell->getControls()->add($control);
+ if($control instanceof IItemDataRenderer)
+ {
+ $control->setItemIndex($cell->getParent()->getItemIndex());
+ $control->setItemType($itemType);
+ }
+ if($control instanceof IDataRenderer)
+ $control->attachEventHandler('OnDataBinding',array($this,'dataBindColumn'));
+ }
+ else if($template!==null)
+ $template->instantiateIn($cell);
+ else if($itemType!==TListItemType::EditItem)
+ $cell->setText('&nbsp;');
+ }
+ else if($itemType===TListItemType::Header)
+ {
+ if(($classPath=$this->getHeaderRenderer())!=='')
+ $this->initializeHeaderCell($cell,$columnIndex);
+ else if($this->_headerTemplate!==null)
+ $this->_headerTemplate->instantiateIn($cell);
+ else
+ $this->initializeHeaderCell($cell,$columnIndex);
+ }
+ else if($itemType===TListItemType::Footer)
+ {
+ if(($classPath=$this->getFooterRenderer())!=='')
+ $this->initializeFooterCell($cell,$columnIndex);
+ else if($this->_footerTemplate!==null)
+ $this->_footerTemplate->instantiateIn($cell);
+ else
+ $this->initializeFooterCell($cell,$columnIndex);
+ }
+ }
+
+ /**
+ * Databinds a cell in the column.
+ * This method is invoked when datagrid performs databinding.
+ * It populates the content of the cell with the relevant data from data source.
+ */
+ public function dataBindColumn($sender,$param)
+ {
+ $item=$sender->getNamingContainer();
+ $sender->setData($item->getData());
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TTextBox.php b/framework/Web/UI/WebControls/TTextBox.php
index 7a9f0445..5cd1149a 100644
--- a/framework/Web/UI/WebControls/TTextBox.php
+++ b/framework/Web/UI/WebControls/TTextBox.php
@@ -1,652 +1,652 @@
-<?php
-/**
- * TTextBox class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTextBox class
- *
- * TTextBox displays a text box on the Web page for user input.
- * The text displayed in the TTextBox control is determined by the
- * {@link setText Text} property. You can create a <b>SingleLine</b>,
- * a <b>MultiLine</b>, or a <b>Password</b> text box by setting
- * the {@link setTextMode TextMode} property. If the TTextBox control
- * is a multiline text box, the number of rows it displays is determined
- * by the {@link setRows Rows} property, and the {@link setWrap Wrap} property
- * can be used to determine whether to wrap the text in the component.
- *
- * To specify the display width of the text box, in characters, set
- * the {@link setColumns Columns} property. To prevent the text displayed
- * in the component from being modified, set the {@link setReadOnly ReadOnly}
- * property to true. If you want to limit the user input to a specified number
- * of characters, set the {@link setMaxLength MaxLength} property.
- * To use AutoComplete feature, set the {@link setAutoCompleteType AutoCompleteType} property.
- *
- * If {@link setAutoPostBack AutoPostBack} is set true, updating the text box
- * and then changing the focus out of it will cause postback action.
- * And if {@link setCausesValidation CausesValidation} is true, validation will
- * also be processed, which can be further restricted within
- * a {@link setValidationGroup ValidationGroup}.
- *
- * WARNING: Be careful if you want to display the text collected via TTextBox.
- * Malicious cross-site script may be injected in. You may use {@link getSafeText SafeText}
- * to prevent this problem.
- *
- * NOTE: If you set {@link setWrap Wrap} to false or use {@link setAutoCompleteType AutoCompleteType},
- * the generated HTML output for the textbox will not be XHTML-compatible.
- * Currently, no alternatives are available.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer
-{
- /**
- * Default number of rows (for MultiLine text box)
- */
- const DEFAULT_ROWS=4;
- /**
- * Default number of columns (for MultiLine text box)
- */
- const DEFAULT_COLUMNS=20;
- /**
- * @var mixed safe text parser
- */
- private static $_safeTextParser=null;
- /**
- * @var string safe textbox content with javascript stripped off
- */
- private $_safeText;
- private $_dataChanged=false;
- private $_isValid=true;
-
- /**
- * @return string tag name of the textbox
- */
- protected function getTagName()
- {
- return ($this->getTextMode()==='MultiLine')?'textarea':'input';
- }
-
- /**
- * @return boolean whether to render javascript.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether to render javascript.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * Adds attribute name-value pairs to renderer.
- * This method overrides the parent implementation with additional textbox specific attributes.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function addAttributesToRender($writer)
- {
- $page=$this->getPage();
- $page->ensureRenderInForm($this);
- if(($uid=$this->getUniqueID())!=='')
- $writer->addAttribute('name',$uid);
- if(($textMode=$this->getTextMode())===TTextBoxMode::MultiLine)
- {
- if(($rows=$this->getRows())<=0)
- $rows=self::DEFAULT_ROWS;
- if(($cols=$this->getColumns())<=0)
- $cols=self::DEFAULT_COLUMNS;
- $writer->addAttribute('rows',"$rows");
- $writer->addAttribute('cols',"$cols");
- if(!$this->getWrap())
- $writer->addAttribute('wrap','off');
- }
- else
- {
- if($textMode===TTextBoxMode::SingleLine)
- {
- $writer->addAttribute('type','text');
- if(($text=$this->getText())!=='')
- $writer->addAttribute('value',$text);
- }
- else
- {
- if($this->getPersistPassword() && ($text=$this->getText())!=='')
- $writer->addAttribute('value',$text);
- $writer->addAttribute('type','password');
- }
-
- if(($act=$this->getAutoCompleteType())!=='None')
- {
- if($act==='Disabled')
- $writer->addAttribute('autocomplete','off');
- else if($act==='Search')
- $writer->addAttribute('vcard_name','search');
- else if($act==='HomeCountryRegion')
- $writer->addAttribute('vcard_name','HomeCountry');
- else if($act==='BusinessCountryRegion')
- $writer->addAttribute('vcard_name','BusinessCountry');
- else
- {
- if(strpos($act,'Business')===0)
- $act='Business'.'.'.substr($act,8);
- else if(strpos($act,'Home')===0)
- $act='Home'.'.'.substr($act,4);
- $writer->addAttribute('vcard_name','vCard.'.$act);
- }
- }
-
- if(($cols=$this->getColumns())>0)
- $writer->addAttribute('size',"$cols");
- if(($maxLength=$this->getMaxLength())>0)
- $writer->addAttribute('maxlength',"$maxLength");
- }
- if($this->getReadOnly())
- $writer->addAttribute('readonly','readonly');
- $isEnabled=$this->getEnabled(true);
- if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
- $writer->addAttribute('disabled','disabled');
- if($isEnabled
- && $this->getEnableClientScript()
- && ( $this->getAutoPostBack() || $textMode===TTextBoxMode::SingleLine)
- && $page->getClientSupportsJavaScript())
- {
- $this->renderClientControlScript($writer);
- }
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Renders the javascript for textbox.
- */
- protected function renderClientControlScript($writer)
- {
- $writer->addAttribute('id',$this->getClientID());
- $cs = $this->getPage()->getClientScript();
- $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
- }
-
- /**
- * Gets the name of the javascript class responsible for performing postback for this control.
- * This method overrides the parent implementation.
- * @return string the javascript class name
- */
- protected function getClientClassName()
- {
- return 'Prado.WebUI.TTextBox';
- }
-
- /**
- * Gets the post back options for this textbox.
- * @return array
- */
- protected function getPostBackOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['AutoPostBack'] = $this->getAutoPostBack();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['TextMode'] = $this->getTextMode();
- return $options;
- }
-
- /**
- * Loads user input data.
- * This method is primarly used by framework developers.
- * @param string the key that can be used to retrieve data from the input data collection
- * @param array the input data collection
- * @return boolean whether the data of the component has been changed
- */
- public function loadPostData($key,$values)
- {
- $value=$values[$key];
- if($this->getAutoTrim())
- $value=trim($value);
- if(!$this->getReadOnly() && $this->getText()!==$value)
- {
- $this->setText($value);
- return $this->_dataChanged=true;
- }
- else
- return false;
- }
-
- /**
- * Returns a value indicating whether postback has caused the control data change.
- * This method is required by the IPostBackDataHandler interface.
- * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
- */
- public function getDataChanged()
- {
- return $this->_dataChanged;
- }
-
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getText();
- }
-
- /**
- * Returns true if this control validated successfully.
- * Defaults to true.
- * @return bool wether this control validated successfully.
- */
- public function getIsValid()
- {
- return $this->_isValid;
- }
- /**
- * @param bool wether this control is valid.
- */
- public function setIsValid($value)
- {
- $this->_isValid=TPropertyValue::ensureBoolean($value);
- }
-
- /**
- * Raises <b>OnTextChanged</b> event.
- * This method is invoked when the value of the {@link getText Text}
- * property changes on postback.
- * If you override this method, be sure to call the parent implementation to ensure
- * the invocation of the attached event handlers.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onTextChanged($param)
- {
- $this->raiseEvent('OnTextChanged',$this,$param);
- }
-
- /**
- * Raises postdata changed event.
- * This method is required by {@link IPostBackDataHandler} interface.
- * It is invoked by the framework when {@link getText Text} property
- * is changed on postback.
- * This method is primarly used by framework developers.
- */
- public function raisePostDataChangedEvent()
- {
- if($this->getAutoPostBack() && $this->getCausesValidation())
- $this->getPage()->validate($this->getValidationGroup());
- $this->onTextChanged(null);
- }
-
- /**
- * Renders the body content of the textbox when it is in MultiLine text mode.
- * @param THtmlWriter the writer for rendering
- */
- public function renderContents($writer)
- {
- if($this->getTextMode()==='MultiLine')
- $writer->write(THttpUtility::htmlEncode($this->getText()));
- }
-
- /**
- * Renders an additional line-break after the opening tag when it
- * is in MultiLine text mode.
- * @param THtmlWriter the writer used for the rendering purpose^M
- */
- public function renderBeginTag($writer)
- {
- parent::renderBeginTag($writer);
- if($this->getTextMode()==='MultiLine')
- $writer->write("\n");
- }
-
- /**
- * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox
- */
- public function getAutoCompleteType()
- {
- return $this->getViewState('AutoCompleteType',TTextBoxAutoCompleteType::None);
- }
-
- /**
- * @param TTextBoxAutoCompleteType the AutoComplete type of the textbox, default value is TTextBoxAutoCompleteType::None.
- * @throws TInvalidDataValueException if the input parameter is not a valid AutoComplete type
- */
- public function setAutoCompleteType($value)
- {
- $this->setViewState('AutoCompleteType',TPropertyValue::ensureEnum($value,'TTextBoxAutoCompleteType'),TTextBoxAutoCompleteType::None);
- }
-
- /**
- * @return boolean a value indicating whether an automatic postback to the server
- * will occur whenever the user modifies the text in the TTextBox control and
- * then tabs out of the component. Defaults to false.
- */
- public function getAutoPostBack()
- {
- return $this->getViewState('AutoPostBack',false);
- }
-
- /**
- * Sets the value indicating if postback automatically.
- * An automatic postback to the server will occur whenever the user
- * modifies the text in the TTextBox control and then tabs out of the component.
- * @param boolean the value indicating if postback automatically
- */
- public function setAutoPostBack($value)
- {
- $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean a value indicating whether the input text should be trimmed spaces. Defaults to false.
- */
- public function getAutoTrim()
- {
- return $this->getViewState('AutoTrim',false);
- }
-
- /**
- * Sets the value indicating if the input text should be trimmed spaces
- * @param boolean the value indicating if the input text should be trimmed spaces
- */
- public function setAutoTrim($value)
- {
- $this->setViewState('AutoTrim',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether postback event trigger by this text box will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this text box will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return integer the display width of the text box in characters, default is 0 meaning not set.
- */
- public function getColumns()
- {
- return $this->getViewState('Columns',0);
- }
-
- /**
- * Sets the display width of the text box in characters.
- * @param integer the display width, set it 0 to clear the setting
- */
- public function setColumns($value)
- {
- $this->setViewState('Columns',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return integer the maximum number of characters allowed in the text box, default is 0 meaning not set.
- */
- public function getMaxLength()
- {
- return $this->getViewState('MaxLength',0);
- }
-
- /**
- * Sets the maximum number of characters allowed in the text box.
- * @param integer the maximum length, set it 0 to clear the setting
- */
- public function setMaxLength($value)
- {
- $this->setViewState('MaxLength',TPropertyValue::ensureInteger($value),0);
- }
-
- /**
- * @return boolean whether the textbox is read only, default is false.
- */
- public function getReadOnly()
- {
- return $this->getViewState('ReadOnly',false);
- }
-
- /**
- * @param boolean whether the textbox is read only
- */
- public function setReadOnly($value)
- {
- $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer the number of rows displayed in a multiline text box, default is 4
- */
- public function getRows()
- {
- return $this->getViewState('Rows',self::DEFAULT_ROWS);
- }
-
- /**
- * Sets the number of rows displayed in a multiline text box.
- * @param integer the number of rows
- */
- public function setRows($value)
- {
- $this->setViewState('Rows',TPropertyValue::ensureInteger($value),self::DEFAULT_ROWS);
- }
-
- /**
- * @return boolean whether password should be displayed in the textbox during postback. Defaults to false. This property only applies when TextMode='Password'.
- */
- public function getPersistPassword()
- {
- return $this->getViewState('PersistPassword',false);
- }
-
- /**
- * @param boolean whether password should be displayed in the textbox during postback. This property only applies when TextMode='Password'.
- */
- public function setPersistPassword($value)
- {
- $this->setViewState('PersistPassword',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return string the text content of the TTextBox control.
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * Sets the text content of the TTextBox control.
- * @param string the text content
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value,'');
- $this->_safeText = null;
- }
-
- /**
- * Returns the text content of the TTextBox control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link getText()}.
- * @return string the text content of the TTextBox control.
- * @see getText
- * @since 3.1.0
- */
- public function getData()
- {
- return $this->getText();
- }
-
- /**
- * Sets the text content of the TTextBox control.
- * This method is required by {@link IDataRenderer}.
- * It is the same as {@link setText()}.
- * @param string the text content of the TTextBox control.
- * @see setText
- * @since 3.1.0
- */
- public function setData($value)
- {
- $this->setText($value);
- }
-
- /**
- * @return string safe text content with javascript stripped off
- */
- public function getSafeText()
- {
- if($this->_safeText===null)
- $this->_safeText=$this->getSafeTextParser()->parse($this->getText());
- return $this->_safeText;
- }
-
- /**
- * @return mixed safe text parser
- */
- protected function getSafeTextParser()
- {
- if(!self::$_safeTextParser)
- self::$_safeTextParser=Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
- return self::$_safeTextParser;
- }
-
- /**
- * @return TTextBoxMode the behavior mode of the TTextBox component. Defaults to TTextBoxMode::SingleLine.
- */
- public function getTextMode()
- {
- return $this->getViewState('TextMode',TTextBoxMode::SingleLine);
- }
-
- /**
- * Sets the behavior mode of the TTextBox component.
- * @param TTextBoxMode the text mode
- * @throws TInvalidDataValueException if the input value is not a valid text mode.
- */
- public function setTextMode($value)
- {
- $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,'TTextBoxMode'),TTextBoxMode::SingleLine);
- }
-
- /**
- * @return string the group of validators which the text box causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the text box causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * @return boolean whether the text content wraps within a multiline text box. Defaults to true.
- */
- public function getWrap()
- {
- return $this->getViewState('Wrap',true);
- }
-
- /**
- * Sets the value indicating whether the text content wraps within a multiline text box.
- * @param boolean whether the text content wraps within a multiline text box.
- */
- public function setWrap($value)
- {
- $this->setViewState('Wrap',TPropertyValue::ensureBoolean($value),true);
- }
-}
-
-/**
- * TTextBoxMode class.
- * TTextBoxMode defines the enumerable type for the possible mode
- * that a {@link TTextBox} control could be at.
- *
- * The following enumerable values are defined:
- * - SingleLine: the textbox will be a regular single line input
- * - MultiLine: the textbox will be a textarea allowing multiple line input
- * - Password: the textbox will hide user input like a password input box
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextBoxMode extends TEnumerable
-{
- const SingleLine='SingleLine';
- const MultiLine='MultiLine';
- const Password='Password';
-}
-
-/**
- * TTextBoxAutoCompleteType class.
- * TTextBoxAutoCompleteType defines the possible AutoComplete type that is supported
- * by a {@link TTextBox} control.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TTextBoxAutoCompleteType extends TEnumerable
-{
- const BusinessCity='BusinessCity';
- const BusinessCountryRegion='BusinessCountryRegion';
- const BusinessFax='BusinessFax';
- const BusinessPhone='BusinessPhone';
- const BusinessState='BusinessState';
- const BusinessStreetAddress='BusinessStreetAddress';
- const BusinessUrl='BusinessUrl';
- const BusinessZipCode='BusinessZipCode';
- const Cellular='Cellular';
- const Company='Company';
- const Department='Department';
- const Disabled='Disabled';
- const DisplayName='DisplayName';
- const Email='Email';
- const FirstName='FirstName';
- const Gender='Gender';
- const HomeCity='HomeCity';
- const HomeCountryRegion='HomeCountryRegion';
- const HomeFax='HomeFax';
- const Homepage='Homepage';
- const HomePhone='HomePhone';
- const HomeState='HomeState';
- const HomeStreetAddress='HomeStreetAddress';
- const HomeZipCode='HomeZipCode';
- const JobTitle='JobTitle';
- const LastName='LastName';
- const MiddleName='MiddleName';
- const None='None';
- const Notes='Notes';
- const Office='Office';
- const Pager='Pager';
- const Search='Search';
-}
-
+<?php
+/**
+ * TTextBox class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTextBox class
+ *
+ * TTextBox displays a text box on the Web page for user input.
+ * The text displayed in the TTextBox control is determined by the
+ * {@link setText Text} property. You can create a <b>SingleLine</b>,
+ * a <b>MultiLine</b>, or a <b>Password</b> text box by setting
+ * the {@link setTextMode TextMode} property. If the TTextBox control
+ * is a multiline text box, the number of rows it displays is determined
+ * by the {@link setRows Rows} property, and the {@link setWrap Wrap} property
+ * can be used to determine whether to wrap the text in the component.
+ *
+ * To specify the display width of the text box, in characters, set
+ * the {@link setColumns Columns} property. To prevent the text displayed
+ * in the component from being modified, set the {@link setReadOnly ReadOnly}
+ * property to true. If you want to limit the user input to a specified number
+ * of characters, set the {@link setMaxLength MaxLength} property.
+ * To use AutoComplete feature, set the {@link setAutoCompleteType AutoCompleteType} property.
+ *
+ * If {@link setAutoPostBack AutoPostBack} is set true, updating the text box
+ * and then changing the focus out of it will cause postback action.
+ * And if {@link setCausesValidation CausesValidation} is true, validation will
+ * also be processed, which can be further restricted within
+ * a {@link setValidationGroup ValidationGroup}.
+ *
+ * WARNING: Be careful if you want to display the text collected via TTextBox.
+ * Malicious cross-site script may be injected in. You may use {@link getSafeText SafeText}
+ * to prevent this problem.
+ *
+ * NOTE: If you set {@link setWrap Wrap} to false or use {@link setAutoCompleteType AutoCompleteType},
+ * the generated HTML output for the textbox will not be XHTML-compatible.
+ * Currently, no alternatives are available.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTextBox extends TWebControl implements IPostBackDataHandler, IValidatable, IDataRenderer
+{
+ /**
+ * Default number of rows (for MultiLine text box)
+ */
+ const DEFAULT_ROWS=4;
+ /**
+ * Default number of columns (for MultiLine text box)
+ */
+ const DEFAULT_COLUMNS=20;
+ /**
+ * @var mixed safe text parser
+ */
+ private static $_safeTextParser=null;
+ /**
+ * @var string safe textbox content with javascript stripped off
+ */
+ private $_safeText;
+ private $_dataChanged=false;
+ private $_isValid=true;
+
+ /**
+ * @return string tag name of the textbox
+ */
+ protected function getTagName()
+ {
+ return ($this->getTextMode()==='MultiLine')?'textarea':'input';
+ }
+
+ /**
+ * @return boolean whether to render javascript.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether to render javascript.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * Adds attribute name-value pairs to renderer.
+ * This method overrides the parent implementation with additional textbox specific attributes.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function addAttributesToRender($writer)
+ {
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ if(($uid=$this->getUniqueID())!=='')
+ $writer->addAttribute('name',$uid);
+ if(($textMode=$this->getTextMode())===TTextBoxMode::MultiLine)
+ {
+ if(($rows=$this->getRows())<=0)
+ $rows=self::DEFAULT_ROWS;
+ if(($cols=$this->getColumns())<=0)
+ $cols=self::DEFAULT_COLUMNS;
+ $writer->addAttribute('rows',"$rows");
+ $writer->addAttribute('cols',"$cols");
+ if(!$this->getWrap())
+ $writer->addAttribute('wrap','off');
+ }
+ else
+ {
+ if($textMode===TTextBoxMode::SingleLine)
+ {
+ $writer->addAttribute('type','text');
+ if(($text=$this->getText())!=='')
+ $writer->addAttribute('value',$text);
+ }
+ else
+ {
+ if($this->getPersistPassword() && ($text=$this->getText())!=='')
+ $writer->addAttribute('value',$text);
+ $writer->addAttribute('type','password');
+ }
+
+ if(($act=$this->getAutoCompleteType())!=='None')
+ {
+ if($act==='Disabled')
+ $writer->addAttribute('autocomplete','off');
+ else if($act==='Search')
+ $writer->addAttribute('vcard_name','search');
+ else if($act==='HomeCountryRegion')
+ $writer->addAttribute('vcard_name','HomeCountry');
+ else if($act==='BusinessCountryRegion')
+ $writer->addAttribute('vcard_name','BusinessCountry');
+ else
+ {
+ if(strpos($act,'Business')===0)
+ $act='Business'.'.'.substr($act,8);
+ else if(strpos($act,'Home')===0)
+ $act='Home'.'.'.substr($act,4);
+ $writer->addAttribute('vcard_name','vCard.'.$act);
+ }
+ }
+
+ if(($cols=$this->getColumns())>0)
+ $writer->addAttribute('size',"$cols");
+ if(($maxLength=$this->getMaxLength())>0)
+ $writer->addAttribute('maxlength',"$maxLength");
+ }
+ if($this->getReadOnly())
+ $writer->addAttribute('readonly','readonly');
+ $isEnabled=$this->getEnabled(true);
+ if(!$isEnabled && $this->getEnabled()) // in this case parent will not render 'disabled'
+ $writer->addAttribute('disabled','disabled');
+ if($isEnabled
+ && $this->getEnableClientScript()
+ && ( $this->getAutoPostBack() || $textMode===TTextBoxMode::SingleLine)
+ && $page->getClientSupportsJavaScript())
+ {
+ $this->renderClientControlScript($writer);
+ }
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Renders the javascript for textbox.
+ */
+ protected function renderClientControlScript($writer)
+ {
+ $writer->addAttribute('id',$this->getClientID());
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPostBackControl($this->getClientClassName(),$this->getPostBackOptions());
+ }
+
+ /**
+ * Gets the name of the javascript class responsible for performing postback for this control.
+ * This method overrides the parent implementation.
+ * @return string the javascript class name
+ */
+ protected function getClientClassName()
+ {
+ return 'Prado.WebUI.TTextBox';
+ }
+
+ /**
+ * Gets the post back options for this textbox.
+ * @return array
+ */
+ protected function getPostBackOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['EventTarget'] = $this->getUniqueID();
+ $options['AutoPostBack'] = $this->getAutoPostBack();
+ $options['CausesValidation'] = $this->getCausesValidation();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['TextMode'] = $this->getTextMode();
+ return $options;
+ }
+
+ /**
+ * Loads user input data.
+ * This method is primarly used by framework developers.
+ * @param string the key that can be used to retrieve data from the input data collection
+ * @param array the input data collection
+ * @return boolean whether the data of the component has been changed
+ */
+ public function loadPostData($key,$values)
+ {
+ $value=$values[$key];
+ if($this->getAutoTrim())
+ $value=trim($value);
+ if(!$this->getReadOnly() && $this->getText()!==$value)
+ {
+ $this->setText($value);
+ return $this->_dataChanged=true;
+ }
+ else
+ return false;
+ }
+
+ /**
+ * Returns a value indicating whether postback has caused the control data change.
+ * This method is required by the IPostBackDataHandler interface.
+ * @return boolean whether postback has caused the control data change. False if the page is not in postback mode.
+ */
+ public function getDataChanged()
+ {
+ return $this->_dataChanged;
+ }
+
+ /**
+ * Returns the value to be validated.
+ * This methid is required by IValidatable interface.
+ * @return mixed the value of the property to be validated.
+ */
+ public function getValidationPropertyValue()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Returns true if this control validated successfully.
+ * Defaults to true.
+ * @return bool wether this control validated successfully.
+ */
+ public function getIsValid()
+ {
+ return $this->_isValid;
+ }
+ /**
+ * @param bool wether this control is valid.
+ */
+ public function setIsValid($value)
+ {
+ $this->_isValid=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
+ * Raises <b>OnTextChanged</b> event.
+ * This method is invoked when the value of the {@link getText Text}
+ * property changes on postback.
+ * If you override this method, be sure to call the parent implementation to ensure
+ * the invocation of the attached event handlers.
+ * @param TEventParameter event parameter to be passed to the event handlers
+ */
+ public function onTextChanged($param)
+ {
+ $this->raiseEvent('OnTextChanged',$this,$param);
+ }
+
+ /**
+ * Raises postdata changed event.
+ * This method is required by {@link IPostBackDataHandler} interface.
+ * It is invoked by the framework when {@link getText Text} property
+ * is changed on postback.
+ * This method is primarly used by framework developers.
+ */
+ public function raisePostDataChangedEvent()
+ {
+ if($this->getAutoPostBack() && $this->getCausesValidation())
+ $this->getPage()->validate($this->getValidationGroup());
+ $this->onTextChanged(null);
+ }
+
+ /**
+ * Renders the body content of the textbox when it is in MultiLine text mode.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
+ {
+ if($this->getTextMode()==='MultiLine')
+ $writer->write(THttpUtility::htmlEncode($this->getText()));
+ }
+
+ /**
+ * Renders an additional line-break after the opening tag when it
+ * is in MultiLine text mode.
+ * @param THtmlWriter the writer used for the rendering purpose^M
+ */
+ public function renderBeginTag($writer)
+ {
+ parent::renderBeginTag($writer);
+ if($this->getTextMode()==='MultiLine')
+ $writer->write("\n");
+ }
+
+ /**
+ * @return TTextBoxAutoCompleteType the AutoComplete type of the textbox
+ */
+ public function getAutoCompleteType()
+ {
+ return $this->getViewState('AutoCompleteType',TTextBoxAutoCompleteType::None);
+ }
+
+ /**
+ * @param TTextBoxAutoCompleteType the AutoComplete type of the textbox, default value is TTextBoxAutoCompleteType::None.
+ * @throws TInvalidDataValueException if the input parameter is not a valid AutoComplete type
+ */
+ public function setAutoCompleteType($value)
+ {
+ $this->setViewState('AutoCompleteType',TPropertyValue::ensureEnum($value,'TTextBoxAutoCompleteType'),TTextBoxAutoCompleteType::None);
+ }
+
+ /**
+ * @return boolean a value indicating whether an automatic postback to the server
+ * will occur whenever the user modifies the text in the TTextBox control and
+ * then tabs out of the component. Defaults to false.
+ */
+ public function getAutoPostBack()
+ {
+ return $this->getViewState('AutoPostBack',false);
+ }
+
+ /**
+ * Sets the value indicating if postback automatically.
+ * An automatic postback to the server will occur whenever the user
+ * modifies the text in the TTextBox control and then tabs out of the component.
+ * @param boolean the value indicating if postback automatically
+ */
+ public function setAutoPostBack($value)
+ {
+ $this->setViewState('AutoPostBack',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean a value indicating whether the input text should be trimmed spaces. Defaults to false.
+ */
+ public function getAutoTrim()
+ {
+ return $this->getViewState('AutoTrim',false);
+ }
+
+ /**
+ * Sets the value indicating if the input text should be trimmed spaces
+ * @param boolean the value indicating if the input text should be trimmed spaces
+ */
+ public function setAutoTrim($value)
+ {
+ $this->setViewState('AutoTrim',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether postback event trigger by this text box will cause input validation, default is true.
+ */
+ public function getCausesValidation()
+ {
+ return $this->getViewState('CausesValidation',true);
+ }
+
+ /**
+ * @param boolean whether postback event trigger by this text box will cause input validation.
+ */
+ public function setCausesValidation($value)
+ {
+ $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return integer the display width of the text box in characters, default is 0 meaning not set.
+ */
+ public function getColumns()
+ {
+ return $this->getViewState('Columns',0);
+ }
+
+ /**
+ * Sets the display width of the text box in characters.
+ * @param integer the display width, set it 0 to clear the setting
+ */
+ public function setColumns($value)
+ {
+ $this->setViewState('Columns',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return integer the maximum number of characters allowed in the text box, default is 0 meaning not set.
+ */
+ public function getMaxLength()
+ {
+ return $this->getViewState('MaxLength',0);
+ }
+
+ /**
+ * Sets the maximum number of characters allowed in the text box.
+ * @param integer the maximum length, set it 0 to clear the setting
+ */
+ public function setMaxLength($value)
+ {
+ $this->setViewState('MaxLength',TPropertyValue::ensureInteger($value),0);
+ }
+
+ /**
+ * @return boolean whether the textbox is read only, default is false.
+ */
+ public function getReadOnly()
+ {
+ return $this->getViewState('ReadOnly',false);
+ }
+
+ /**
+ * @param boolean whether the textbox is read only
+ */
+ public function setReadOnly($value)
+ {
+ $this->setViewState('ReadOnly',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the number of rows displayed in a multiline text box, default is 4
+ */
+ public function getRows()
+ {
+ return $this->getViewState('Rows',self::DEFAULT_ROWS);
+ }
+
+ /**
+ * Sets the number of rows displayed in a multiline text box.
+ * @param integer the number of rows
+ */
+ public function setRows($value)
+ {
+ $this->setViewState('Rows',TPropertyValue::ensureInteger($value),self::DEFAULT_ROWS);
+ }
+
+ /**
+ * @return boolean whether password should be displayed in the textbox during postback. Defaults to false. This property only applies when TextMode='Password'.
+ */
+ public function getPersistPassword()
+ {
+ return $this->getViewState('PersistPassword',false);
+ }
+
+ /**
+ * @param boolean whether password should be displayed in the textbox during postback. This property only applies when TextMode='Password'.
+ */
+ public function setPersistPassword($value)
+ {
+ $this->setViewState('PersistPassword',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return string the text content of the TTextBox control.
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * Sets the text content of the TTextBox control.
+ * @param string the text content
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value,'');
+ $this->_safeText = null;
+ }
+
+ /**
+ * Returns the text content of the TTextBox control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link getText()}.
+ * @return string the text content of the TTextBox control.
+ * @see getText
+ * @since 3.1.0
+ */
+ public function getData()
+ {
+ return $this->getText();
+ }
+
+ /**
+ * Sets the text content of the TTextBox control.
+ * This method is required by {@link IDataRenderer}.
+ * It is the same as {@link setText()}.
+ * @param string the text content of the TTextBox control.
+ * @see setText
+ * @since 3.1.0
+ */
+ public function setData($value)
+ {
+ $this->setText($value);
+ }
+
+ /**
+ * @return string safe text content with javascript stripped off
+ */
+ public function getSafeText()
+ {
+ if($this->_safeText===null)
+ $this->_safeText=$this->getSafeTextParser()->parse($this->getText());
+ return $this->_safeText;
+ }
+
+ /**
+ * @return mixed safe text parser
+ */
+ protected function getSafeTextParser()
+ {
+ if(!self::$_safeTextParser)
+ self::$_safeTextParser=Prado::createComponent('System.3rdParty.SafeHtml.TSafeHtmlParser');
+ return self::$_safeTextParser;
+ }
+
+ /**
+ * @return TTextBoxMode the behavior mode of the TTextBox component. Defaults to TTextBoxMode::SingleLine.
+ */
+ public function getTextMode()
+ {
+ return $this->getViewState('TextMode',TTextBoxMode::SingleLine);
+ }
+
+ /**
+ * Sets the behavior mode of the TTextBox component.
+ * @param TTextBoxMode the text mode
+ * @throws TInvalidDataValueException if the input value is not a valid text mode.
+ */
+ public function setTextMode($value)
+ {
+ $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,'TTextBoxMode'),TTextBoxMode::SingleLine);
+ }
+
+ /**
+ * @return string the group of validators which the text box causes validation upon postback
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group of validators which the text box causes validation upon postback
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ /**
+ * @return boolean whether the text content wraps within a multiline text box. Defaults to true.
+ */
+ public function getWrap()
+ {
+ return $this->getViewState('Wrap',true);
+ }
+
+ /**
+ * Sets the value indicating whether the text content wraps within a multiline text box.
+ * @param boolean whether the text content wraps within a multiline text box.
+ */
+ public function setWrap($value)
+ {
+ $this->setViewState('Wrap',TPropertyValue::ensureBoolean($value),true);
+ }
+}
+
+/**
+ * TTextBoxMode class.
+ * TTextBoxMode defines the enumerable type for the possible mode
+ * that a {@link TTextBox} control could be at.
+ *
+ * The following enumerable values are defined:
+ * - SingleLine: the textbox will be a regular single line input
+ * - MultiLine: the textbox will be a textarea allowing multiple line input
+ * - Password: the textbox will hide user input like a password input box
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextBoxMode extends TEnumerable
+{
+ const SingleLine='SingleLine';
+ const MultiLine='MultiLine';
+ const Password='Password';
+}
+
+/**
+ * TTextBoxAutoCompleteType class.
+ * TTextBoxAutoCompleteType defines the possible AutoComplete type that is supported
+ * by a {@link TTextBox} control.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TTextBoxAutoCompleteType extends TEnumerable
+{
+ const BusinessCity='BusinessCity';
+ const BusinessCountryRegion='BusinessCountryRegion';
+ const BusinessFax='BusinessFax';
+ const BusinessPhone='BusinessPhone';
+ const BusinessState='BusinessState';
+ const BusinessStreetAddress='BusinessStreetAddress';
+ const BusinessUrl='BusinessUrl';
+ const BusinessZipCode='BusinessZipCode';
+ const Cellular='Cellular';
+ const Company='Company';
+ const Department='Department';
+ const Disabled='Disabled';
+ const DisplayName='DisplayName';
+ const Email='Email';
+ const FirstName='FirstName';
+ const Gender='Gender';
+ const HomeCity='HomeCity';
+ const HomeCountryRegion='HomeCountryRegion';
+ const HomeFax='HomeFax';
+ const Homepage='Homepage';
+ const HomePhone='HomePhone';
+ const HomeState='HomeState';
+ const HomeStreetAddress='HomeStreetAddress';
+ const HomeZipCode='HomeZipCode';
+ const JobTitle='JobTitle';
+ const LastName='LastName';
+ const MiddleName='MiddleName';
+ const None='None';
+ const Notes='Notes';
+ const Office='Office';
+ const Pager='Pager';
+ const Search='Search';
+}
+
diff --git a/framework/Web/UI/WebControls/TTextProcessor.php b/framework/Web/UI/WebControls/TTextProcessor.php
index 6d95a482..60d047fe 100644
--- a/framework/Web/UI/WebControls/TTextProcessor.php
+++ b/framework/Web/UI/WebControls/TTextProcessor.php
@@ -1,86 +1,86 @@
-<?php
-/**
- * TTextProcessor class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TTextProcessor class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TTextProcessor class.
- *
- * TTextProcessor is the base class for classes that process or transform
- * text content into different forms. The text content to be processed
- * is specified by {@link setText Text} property. If it is not set, the body
- * content enclosed within the processor control will be processed and rendered.
- * The body content includes static text strings and the rendering result
- * of child controls.
- *
- * Note, all child classes must implement {@link processText} method.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI
- * @since 3.0.1
- */
-abstract class TTextProcessor extends TWebControl
-{
- /**
- * Processes a text string.
- * This method must be implemented by child classes.
- * @param string text string to be processed
- * @return string the processed text result
- */
- abstract public function processText($text);
-
- /**
- * HTML-decodes static text.
- * This method overrides parent implementation.
- * @param mixed object to be added as body content
- */
- public function addParsedObject($object)
- {
- if(is_string($object))
- $object=html_entity_decode($object,ENT_QUOTES,'UTF-8');
- parent::addParsedObject($object);
- }
-
- /**
- * @return string text to be processed
- */
- public function getText()
- {
- return $this->getViewState('Text','');
- }
-
- /**
- * @param string text to be processed
- */
- public function setText($value)
- {
- $this->setViewState('Text',$value);
- }
-
- /**
- * Renders body content.
- * This method overrides the parent implementation by replacing
- * the body content with the processed text content.
- * @param THtmlWriter writer
- */
- public function renderContents($writer)
- {
- if(($text=$this->getText())==='' && $this->getHasControls())
- {
- $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
- parent::renderContents($htmlWriter);
- $text=$htmlWriter->flush();
- }
- if($text!=='')
- $writer->write($this->processText($text));
- }
-
-}
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TTextProcessor class.
+ *
+ * TTextProcessor is the base class for classes that process or transform
+ * text content into different forms. The text content to be processed
+ * is specified by {@link setText Text} property. If it is not set, the body
+ * content enclosed within the processor control will be processed and rendered.
+ * The body content includes static text strings and the rendering result
+ * of child controls.
+ *
+ * Note, all child classes must implement {@link processText} method.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI
+ * @since 3.0.1
+ */
+abstract class TTextProcessor extends TWebControl
+{
+ /**
+ * Processes a text string.
+ * This method must be implemented by child classes.
+ * @param string text string to be processed
+ * @return string the processed text result
+ */
+ abstract public function processText($text);
+
+ /**
+ * HTML-decodes static text.
+ * This method overrides parent implementation.
+ * @param mixed object to be added as body content
+ */
+ public function addParsedObject($object)
+ {
+ if(is_string($object))
+ $object=html_entity_decode($object,ENT_QUOTES,'UTF-8');
+ parent::addParsedObject($object);
+ }
+
+ /**
+ * @return string text to be processed
+ */
+ public function getText()
+ {
+ return $this->getViewState('Text','');
+ }
+
+ /**
+ * @param string text to be processed
+ */
+ public function setText($value)
+ {
+ $this->setViewState('Text',$value);
+ }
+
+ /**
+ * Renders body content.
+ * This method overrides the parent implementation by replacing
+ * the body content with the processed text content.
+ * @param THtmlWriter writer
+ */
+ public function renderContents($writer)
+ {
+ if(($text=$this->getText())==='' && $this->getHasControls())
+ {
+ $htmlWriter = Prado::createComponent($this->GetResponse()->getHtmlWriterType(), new TTextWriter());
+ parent::renderContents($htmlWriter);
+ $text=$htmlWriter->flush();
+ }
+ if($text!=='')
+ $writer->write($this->processText($text));
+ }
+
+}
diff --git a/framework/Web/UI/WebControls/TValidationSummary.php b/framework/Web/UI/WebControls/TValidationSummary.php
index 6c258927..c915d163 100644
--- a/framework/Web/UI/WebControls/TValidationSummary.php
+++ b/framework/Web/UI/WebControls/TValidationSummary.php
@@ -1,536 +1,536 @@
-<?php
-/**
- * TValidationSummary class file
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TValidationSummary class
- *
- * TValidationSummary displays a summary of validation errors inline on a Web page,
- * in a message box, or both. By default, a validation summary will collect
- * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators
- * on the page. If {@link getValidationGroup ValidationGroup} is not
- * empty, only those validators who belong to the group will show their error messages
- * in the summary.
- *
- * The summary can be displayed as a list, as a bulleted list, or as a single
- * paragraph based on the {@link setDisplayMode DisplayMode} property.
- * The messages shown can be prefixed with {@link setHeaderText HeaderText}.
- *
- * The summary can be displayed on the Web page and in a message box by setting
- * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox}
- * properties, respectively. Note, the latter is only effective when
- * {@link setEnableClientScript EnableClientScript} is true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TValidationSummary extends TWebControl
-{
- /**
- * @var TClientSideValidationSummaryOptions validation client side options.
- */
- private $_clientSide;
-
- /**
- * Constructor.
- * This method sets the foreground color to red.
- */
- public function __construct()
- {
- parent::__construct();
- $this->setForeColor('red');
- }
-
- /**
- * @return TValidationSummaryDisplayStyle the style of displaying the error messages. Defaults to TValidationSummaryDisplayStyle::Fixed.
- */
- public function getDisplay()
- {
- return $this->getViewState('Display',TValidationSummaryDisplayStyle::Fixed);
- }
-
- /**
- * @param TValidationSummaryDisplayStyle the style of displaying the error messages
- */
- public function setDisplay($value)
- {
- $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayStyle'),TValidationSummaryDisplayStyle::Fixed);
- }
-
- /**
- * @return string the header text displayed at the top of the summary
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * Sets the header text to be displayed at the top of the summary
- * @param string the header text
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',$value,'');
- }
-
- /**
- * @return TValidationSummaryDisplayMode the mode of displaying error messages. Defaults to TValidationSummaryDisplayMode::BulletList.
- */
- public function getDisplayMode()
- {
- return $this->getViewState('DisplayMode',TValidationSummaryDisplayMode::BulletList);
- }
-
- /**
- * @param TValidationSummaryDisplayMode the mode of displaying error messages
- */
- public function setDisplayMode($value)
- {
- $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayMode'),TValidationSummaryDisplayMode::BulletList);
- }
-
- /**
- * @return boolean whether the TValidationSummary component updates itself using client-side script. Defaults to true.
- */
- public function getEnableClientScript()
- {
- return $this->getViewState('EnableClientScript',true);
- }
-
- /**
- * @param boolean whether the TValidationSummary component updates itself using client-side script.
- */
- public function setEnableClientScript($value)
- {
- $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the validation summary is displayed in a message box. Defaults to false.
- */
- public function getShowMessageBox()
- {
- return $this->getViewState('ShowMessageBox',false);
- }
-
- /**
- * @param boolean whether the validation summary is displayed in a message box.
- */
- public function setShowMessageBox($value)
- {
- $this->setViewState('ShowMessageBox',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether the validation summary is displayed inline. Defaults to true.
- */
- public function getShowSummary()
- {
- return $this->getViewState('ShowSummary',true);
- }
-
- /**
- * @param boolean whether the validation summary is displayed inline.
- */
- public function setShowSummary($value)
- {
- $this->setViewState('ShowSummary',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether scroll summary into viewport or not. Defaults to true.
- */
- public function getScrollToSummary()
- {
- return $this->getViewState('ScrollToSummary',true);
- }
-
- /**
- * @param boolean whether scroll summary into viewport or not.
- */
- public function setScrollToSummary($value)
- {
- $this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return boolean whether the validation summary should be anchored. Defaults to false.
- */
- public function getShowAnchor()
- {
- return $this->getViewState('ShowAnchor',false);
- }
-
- /**
- * @param boolean whether the validation summary should be anchored.
- */
- public function setShowAnchor($value)
- {
- $this->setViewState('ShowAnchor',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * Gets the auto-update for this summary.
- * @return boolean automatic client-side summary updates. Defaults to true.
- */
- public function getAutoUpdate()
- {
- return $this->getViewState('AutoUpdate', true);
- }
-
- /**
- * Sets the summary to auto-update on the client-side
- * @param boolean true for automatic summary updates.
- */
- public function setAutoUpdate($value)
- {
- $this->setViewState('AutoUpdate', TPropertyValue::ensureBoolean($value), true);
- }
-
- /**
- * @return string the group which this validator belongs to
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group which this validator belongs to
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- protected function addAttributesToRender($writer)
- {
- $display=$this->getDisplay();
- $visible=$this->getEnabled(true) && count($this->getErrorMessages()) > 0;
- if(!$visible)
- {
- if($display===TValidationSummaryDisplayStyle::None || $display===TValidationSummaryDisplayStyle::Dynamic)
- $writer->addStyleAttribute('display','none');
- else
- $writer->addStyleAttribute('visibility','hidden');
- }
- $writer->addAttribute('id',$this->getClientID());
- parent::addAttributesToRender($writer);
- }
-
- /**
- * Render the javascript for validation summary.
- * @param array list of options for validation summary.
- */
- protected function renderJsSummary()
- {
- if(!$this->getEnabled(true) || !$this->getEnableClientScript())
- return;
- $cs = $this->getPage()->getClientScript();
- $cs->registerPradoScript('validator');
-
- //need to register the validation manager is validation summary is alone.
- $formID=$this->getPage()->getForm()->getClientID();
- $scriptKey = "TBaseValidator:$formID";
- if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey))
- {
- $manager['FormID'] = $formID;
- $options = TJavaScript::encode($manager);
- $cs->registerPradoScript('validator');
- $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
- }
-
-
- $options=TJavaScript::encode($this->getClientScriptOptions());
- $script = "new Prado.WebUI.TValidationSummary({$options});";
- $cs->registerEndScript($this->getClientID(), $script);
- }
-
- /**
- * Get a list of options for the client-side javascript validation summary.
- * @return array list of options for the summary
- */
- protected function getClientScriptOptions()
- {
- $options['ID'] = $this->getClientID();
- $options['FormID'] = $this->getPage()->getForm()->getClientID();
- if($this->getShowMessageBox())
- $options['ShowMessageBox']=true;
- if(!$this->getShowSummary())
- $options['ShowSummary']=false;
-
- $options['ScrollToSummary']=$this->getScrollToSummary();
- $options['HeaderText']=$this->getHeaderText();
- $options['DisplayMode']=$this->getDisplayMode();
-
- $options['Refresh'] = $this->getAutoUpdate();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['Display'] = $this->getDisplay();
-
- if($this->_clientSide!==null)
- $options = array_merge($options,$this->_clientSide->getOptions()->toArray());
-
- return $options;
- }
-
- /**
- * @return TClientSideValidationSummaryOptions client-side validation summary
- * event options.
- */
- public function getClientSide()
- {
- if($this->_clientSide===null)
- $this->_clientSide = $this->createClientScript();
- return $this->_clientSide;
- }
-
- /**
- * @return TClientSideValidationSummaryOptions javascript validation summary
- * event options.
- */
- protected function createClientScript()
- {
- return new TClientSideValidationSummaryOptions;
- }
- /**
- * Get the list of validation error messages.
- * @return array list of validator error messages.
- */
- protected function getErrorMessages()
- {
- $validators=$this->getPage()->getValidators($this->getValidationGroup());
- $messages = array();
- foreach($validators as $validator)
- {
- if(!$validator->getIsValid() && ($msg=$validator->getErrorMessage())!=='')
- //$messages[] = $validator->getAnchoredMessage($msg);
- $messages[] = $msg;
- }
- return $messages;
- }
-
- /**
- * Overrides parent implementation by rendering TValidationSummary-specific presentation.
- * @return string the rendering result
- */
- public function renderContents($writer)
- {
- $this->renderJsSummary();
- if($this->getShowSummary())
- {
-// $this->setStyle('display:block');
- switch($this->getDisplayMode())
- {
- case TValidationSummaryDisplayMode::SimpleList:
- $this->renderList($writer);
- break;
- case TValidationSummaryDisplayMode::SingleParagraph:
- $this->renderSingleParagraph($writer);
- break;
- case TValidationSummaryDisplayMode::BulletList:
- $this->renderBulletList($writer);
- break;
- case TValidationSummaryDisplayMode::HeaderOnly:
- $this->renderHeaderOnly($writer);
- break;
- }
- }
- }
-
- /**
- * Render the validation summary as a simple list.
- * @param array list of messages
- * @param string the header text
- * @return string summary list
- */
- protected function renderList($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = '';
- if(strlen($header))
- $content.= $header."<br/>\n";
- foreach($messages as $message)
- $content.="$message<br/>\n";
- $writer->write($content);
- }
-
- /**
- * Render the validation summary as a paragraph.
- * @param array list of messages
- * @param string the header text
- * @return string summary paragraph
- */
- protected function renderSingleParagraph($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = $header;
- foreach($messages as $message)
- $content.= ' '.$message;
- $writer->write($content);
- }
-
- /**
- * Render the validation summary as a bullet list.
- * @param array list of messages
- * @param string the header text
- * @return string summary bullet list
- */
- protected function renderBulletList($writer)
- {
- $header=$this->getHeaderText();
- $messages=$this->getErrorMessages();
- $content = $header;
- if(count($messages)>0)
- {
- $content .= "<ul>\n";
- foreach($messages as $message)
- $content.= '<li>'.$message."</li>\n";
- $content .= "</ul>\n";
- }
- $writer->write($content);
- }
-
- /**
- * Render the validation summary header text only.
- * @param THtmlWriter the writer used for the rendering purpose
- */
- protected function renderHeaderOnly($writer)
- {
- $writer->write($this->getHeaderText());
- }
-}
-
-/**
- * TClientSideValidationSummaryOptions class.
- *
- * Client-side validation summary events such as {@link setOnHideSummary
- * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified
- * through the {@link TBaseValidator:: getClientSide ClientSide} property of a
- * validation summary.
- *
- * The <tt>OnHideSummary</tt> event is raise when the validation summary
- * requests to hide the messages.
- *
- * The <tt>OnShowSummary</tt> event is raised when the validation summary
- * requests to show the messages.
- *
- * See the quickstart documentation for further details.
- *
- * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TClientSideValidationSummaryOptions extends TClientSideOptions
-{
- /**
- * @return string javascript code for client-side OnHideSummary event.
- */
- public function getOnHideSummary()
- {
- return $this->getOption('OnHideSummary');
- }
-
- /**
- * Client-side OnHideSummary validation summary event is raise when all the
- * validators are valid. This will override the default client-side
- * validation summary behaviour.
- * @param string javascript code for client-side OnHideSummary event.
- */
- public function setOnHideSummary($javascript)
- {
- $this->setFunction('OnHideSummary', $javascript);
- }
-
- /**
- * Client-side OnShowSummary event is raise when one or more validators are
- * not valid. This will override the default client-side validation summary
- * behaviour.
- * @param string javascript code for client-side OnShowSummary event.
- */
- public function setOnShowSummary($javascript)
- {
- $this->setFunction('OnShowSummary', $javascript);
- }
-
- /**
- * @return string javascript code for client-side OnShowSummary event.
- */
- public function getOnShowSummary()
- {
- return $this->getOption('OnShowSummary');
- }
-
- /**
- * Ensure the string is a valid javascript function. The code block
- * is enclosed with "function(summary, validators){ }" block.
- * @param string javascript code.
- * @return string javascript function code.
- */
- protected function ensureFunction($javascript)
- {
- return "function(summary, validators){ {$javascript} }";
- }
-}
-
-
-/**
- * TValidationSummaryDisplayMode class.
- * TValidationSummaryDisplayMode defines the enumerable type for the possible modes
- * that a {@link TValidationSummary} can organize and display the collected error messages.
- *
- * The following enumerable values are defined:
- * - SimpleList: the error messages are displayed as a list without any decorations.
- * - SingleParagraph: the error messages are concatenated together into a paragraph.
- * - BulletList: the error messages are displayed as a bulleted list.
- * - HeaderOnly: only the HeaderText will be display.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationSummaryDisplayMode extends TEnumerable
-{
- const SimpleList='SimpleList';
- const SingleParagraph='SingleParagraph';
- const BulletList='BulletList';
- const HeaderOnly='HeaderOnly';
-}
-
-
-/**
- * TValidationSummaryDisplay class.
- * TValidationSummaryDisplay defines the enumerable type for the possible styles
- * that a {@link TValidationSummary} can display the collected error messages.
- *
- * The following enumerable values are defined:
- * - None: the error messages are not displayed
- * - Dynamic: the error messages are dynamically added to display as the corresponding validators fail
- * - Fixed: Similar to Dynamic except that the error messages physically occupy the page layout (even though they may not be visible)
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TValidationSummaryDisplayStyle extends TEnumerable
-{
- const None='None';
- const Dynamic='Dynamic';
- const Fixed='Fixed';
-}
-
+<?php
+/**
+ * TValidationSummary class file
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TValidationSummary class
+ *
+ * TValidationSummary displays a summary of validation errors inline on a Web page,
+ * in a message box, or both. By default, a validation summary will collect
+ * {@link TBaseValidator::getErrorMessage ErrorMessage} of all failed validators
+ * on the page. If {@link getValidationGroup ValidationGroup} is not
+ * empty, only those validators who belong to the group will show their error messages
+ * in the summary.
+ *
+ * The summary can be displayed as a list, as a bulleted list, or as a single
+ * paragraph based on the {@link setDisplayMode DisplayMode} property.
+ * The messages shown can be prefixed with {@link setHeaderText HeaderText}.
+ *
+ * The summary can be displayed on the Web page and in a message box by setting
+ * the {@link setShowSummary ShowSummary} and {@link setShowMessageBox ShowMessageBox}
+ * properties, respectively. Note, the latter is only effective when
+ * {@link setEnableClientScript EnableClientScript} is true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TValidationSummary extends TWebControl
+{
+ /**
+ * @var TClientSideValidationSummaryOptions validation client side options.
+ */
+ private $_clientSide;
+
+ /**
+ * Constructor.
+ * This method sets the foreground color to red.
+ */
+ public function __construct()
+ {
+ parent::__construct();
+ $this->setForeColor('red');
+ }
+
+ /**
+ * @return TValidationSummaryDisplayStyle the style of displaying the error messages. Defaults to TValidationSummaryDisplayStyle::Fixed.
+ */
+ public function getDisplay()
+ {
+ return $this->getViewState('Display',TValidationSummaryDisplayStyle::Fixed);
+ }
+
+ /**
+ * @param TValidationSummaryDisplayStyle the style of displaying the error messages
+ */
+ public function setDisplay($value)
+ {
+ $this->setViewState('Display',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayStyle'),TValidationSummaryDisplayStyle::Fixed);
+ }
+
+ /**
+ * @return string the header text displayed at the top of the summary
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * Sets the header text to be displayed at the top of the summary
+ * @param string the header text
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',$value,'');
+ }
+
+ /**
+ * @return TValidationSummaryDisplayMode the mode of displaying error messages. Defaults to TValidationSummaryDisplayMode::BulletList.
+ */
+ public function getDisplayMode()
+ {
+ return $this->getViewState('DisplayMode',TValidationSummaryDisplayMode::BulletList);
+ }
+
+ /**
+ * @param TValidationSummaryDisplayMode the mode of displaying error messages
+ */
+ public function setDisplayMode($value)
+ {
+ $this->setViewState('DisplayMode',TPropertyValue::ensureEnum($value,'TValidationSummaryDisplayMode'),TValidationSummaryDisplayMode::BulletList);
+ }
+
+ /**
+ * @return boolean whether the TValidationSummary component updates itself using client-side script. Defaults to true.
+ */
+ public function getEnableClientScript()
+ {
+ return $this->getViewState('EnableClientScript',true);
+ }
+
+ /**
+ * @param boolean whether the TValidationSummary component updates itself using client-side script.
+ */
+ public function setEnableClientScript($value)
+ {
+ $this->setViewState('EnableClientScript',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the validation summary is displayed in a message box. Defaults to false.
+ */
+ public function getShowMessageBox()
+ {
+ return $this->getViewState('ShowMessageBox',false);
+ }
+
+ /**
+ * @param boolean whether the validation summary is displayed in a message box.
+ */
+ public function setShowMessageBox($value)
+ {
+ $this->setViewState('ShowMessageBox',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the validation summary is displayed inline. Defaults to true.
+ */
+ public function getShowSummary()
+ {
+ return $this->getViewState('ShowSummary',true);
+ }
+
+ /**
+ * @param boolean whether the validation summary is displayed inline.
+ */
+ public function setShowSummary($value)
+ {
+ $this->setViewState('ShowSummary',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether scroll summary into viewport or not. Defaults to true.
+ */
+ public function getScrollToSummary()
+ {
+ return $this->getViewState('ScrollToSummary',true);
+ }
+
+ /**
+ * @param boolean whether scroll summary into viewport or not.
+ */
+ public function setScrollToSummary($value)
+ {
+ $this->setViewState('ScrollToSummary',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return boolean whether the validation summary should be anchored. Defaults to false.
+ */
+ public function getShowAnchor()
+ {
+ return $this->getViewState('ShowAnchor',false);
+ }
+
+ /**
+ * @param boolean whether the validation summary should be anchored.
+ */
+ public function setShowAnchor($value)
+ {
+ $this->setViewState('ShowAnchor',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * Gets the auto-update for this summary.
+ * @return boolean automatic client-side summary updates. Defaults to true.
+ */
+ public function getAutoUpdate()
+ {
+ return $this->getViewState('AutoUpdate', true);
+ }
+
+ /**
+ * Sets the summary to auto-update on the client-side
+ * @param boolean true for automatic summary updates.
+ */
+ public function setAutoUpdate($value)
+ {
+ $this->setViewState('AutoUpdate', TPropertyValue::ensureBoolean($value), true);
+ }
+
+ /**
+ * @return string the group which this validator belongs to
+ */
+ public function getValidationGroup()
+ {
+ return $this->getViewState('ValidationGroup','');
+ }
+
+ /**
+ * @param string the group which this validator belongs to
+ */
+ public function setValidationGroup($value)
+ {
+ $this->setViewState('ValidationGroup',$value,'');
+ }
+
+ protected function addAttributesToRender($writer)
+ {
+ $display=$this->getDisplay();
+ $visible=$this->getEnabled(true) && count($this->getErrorMessages()) > 0;
+ if(!$visible)
+ {
+ if($display===TValidationSummaryDisplayStyle::None || $display===TValidationSummaryDisplayStyle::Dynamic)
+ $writer->addStyleAttribute('display','none');
+ else
+ $writer->addStyleAttribute('visibility','hidden');
+ }
+ $writer->addAttribute('id',$this->getClientID());
+ parent::addAttributesToRender($writer);
+ }
+
+ /**
+ * Render the javascript for validation summary.
+ * @param array list of options for validation summary.
+ */
+ protected function renderJsSummary()
+ {
+ if(!$this->getEnabled(true) || !$this->getEnableClientScript())
+ return;
+ $cs = $this->getPage()->getClientScript();
+ $cs->registerPradoScript('validator');
+
+ //need to register the validation manager is validation summary is alone.
+ $formID=$this->getPage()->getForm()->getClientID();
+ $scriptKey = "TBaseValidator:$formID";
+ if($this->getEnableClientScript() && !$cs->isEndScriptRegistered($scriptKey))
+ {
+ $manager['FormID'] = $formID;
+ $options = TJavaScript::encode($manager);
+ $cs->registerPradoScript('validator');
+ $cs->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");
+ }
+
+
+ $options=TJavaScript::encode($this->getClientScriptOptions());
+ $script = "new Prado.WebUI.TValidationSummary({$options});";
+ $cs->registerEndScript($this->getClientID(), $script);
+ }
+
+ /**
+ * Get a list of options for the client-side javascript validation summary.
+ * @return array list of options for the summary
+ */
+ protected function getClientScriptOptions()
+ {
+ $options['ID'] = $this->getClientID();
+ $options['FormID'] = $this->getPage()->getForm()->getClientID();
+ if($this->getShowMessageBox())
+ $options['ShowMessageBox']=true;
+ if(!$this->getShowSummary())
+ $options['ShowSummary']=false;
+
+ $options['ScrollToSummary']=$this->getScrollToSummary();
+ $options['HeaderText']=$this->getHeaderText();
+ $options['DisplayMode']=$this->getDisplayMode();
+
+ $options['Refresh'] = $this->getAutoUpdate();
+ $options['ValidationGroup'] = $this->getValidationGroup();
+ $options['Display'] = $this->getDisplay();
+
+ if($this->_clientSide!==null)
+ $options = array_merge($options,$this->_clientSide->getOptions()->toArray());
+
+ return $options;
+ }
+
+ /**
+ * @return TClientSideValidationSummaryOptions client-side validation summary
+ * event options.
+ */
+ public function getClientSide()
+ {
+ if($this->_clientSide===null)
+ $this->_clientSide = $this->createClientScript();
+ return $this->_clientSide;
+ }
+
+ /**
+ * @return TClientSideValidationSummaryOptions javascript validation summary
+ * event options.
+ */
+ protected function createClientScript()
+ {
+ return new TClientSideValidationSummaryOptions;
+ }
+ /**
+ * Get the list of validation error messages.
+ * @return array list of validator error messages.
+ */
+ protected function getErrorMessages()
+ {
+ $validators=$this->getPage()->getValidators($this->getValidationGroup());
+ $messages = array();
+ foreach($validators as $validator)
+ {
+ if(!$validator->getIsValid() && ($msg=$validator->getErrorMessage())!=='')
+ //$messages[] = $validator->getAnchoredMessage($msg);
+ $messages[] = $msg;
+ }
+ return $messages;
+ }
+
+ /**
+ * Overrides parent implementation by rendering TValidationSummary-specific presentation.
+ * @return string the rendering result
+ */
+ public function renderContents($writer)
+ {
+ $this->renderJsSummary();
+ if($this->getShowSummary())
+ {
+// $this->setStyle('display:block');
+ switch($this->getDisplayMode())
+ {
+ case TValidationSummaryDisplayMode::SimpleList:
+ $this->renderList($writer);
+ break;
+ case TValidationSummaryDisplayMode::SingleParagraph:
+ $this->renderSingleParagraph($writer);
+ break;
+ case TValidationSummaryDisplayMode::BulletList:
+ $this->renderBulletList($writer);
+ break;
+ case TValidationSummaryDisplayMode::HeaderOnly:
+ $this->renderHeaderOnly($writer);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Render the validation summary as a simple list.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary list
+ */
+ protected function renderList($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = '';
+ if(strlen($header))
+ $content.= $header."<br/>\n";
+ foreach($messages as $message)
+ $content.="$message<br/>\n";
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary as a paragraph.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary paragraph
+ */
+ protected function renderSingleParagraph($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = $header;
+ foreach($messages as $message)
+ $content.= ' '.$message;
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary as a bullet list.
+ * @param array list of messages
+ * @param string the header text
+ * @return string summary bullet list
+ */
+ protected function renderBulletList($writer)
+ {
+ $header=$this->getHeaderText();
+ $messages=$this->getErrorMessages();
+ $content = $header;
+ if(count($messages)>0)
+ {
+ $content .= "<ul>\n";
+ foreach($messages as $message)
+ $content.= '<li>'.$message."</li>\n";
+ $content .= "</ul>\n";
+ }
+ $writer->write($content);
+ }
+
+ /**
+ * Render the validation summary header text only.
+ * @param THtmlWriter the writer used for the rendering purpose
+ */
+ protected function renderHeaderOnly($writer)
+ {
+ $writer->write($this->getHeaderText());
+ }
+}
+
+/**
+ * TClientSideValidationSummaryOptions class.
+ *
+ * Client-side validation summary events such as {@link setOnHideSummary
+ * OnHideSummary} and {@link setOnShowSummary OnShowSummary} can be modified
+ * through the {@link TBaseValidator:: getClientSide ClientSide} property of a
+ * validation summary.
+ *
+ * The <tt>OnHideSummary</tt> event is raise when the validation summary
+ * requests to hide the messages.
+ *
+ * The <tt>OnShowSummary</tt> event is raised when the validation summary
+ * requests to show the messages.
+ *
+ * See the quickstart documentation for further details.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TClientSideValidationSummaryOptions extends TClientSideOptions
+{
+ /**
+ * @return string javascript code for client-side OnHideSummary event.
+ */
+ public function getOnHideSummary()
+ {
+ return $this->getOption('OnHideSummary');
+ }
+
+ /**
+ * Client-side OnHideSummary validation summary event is raise when all the
+ * validators are valid. This will override the default client-side
+ * validation summary behaviour.
+ * @param string javascript code for client-side OnHideSummary event.
+ */
+ public function setOnHideSummary($javascript)
+ {
+ $this->setFunction('OnHideSummary', $javascript);
+ }
+
+ /**
+ * Client-side OnShowSummary event is raise when one or more validators are
+ * not valid. This will override the default client-side validation summary
+ * behaviour.
+ * @param string javascript code for client-side OnShowSummary event.
+ */
+ public function setOnShowSummary($javascript)
+ {
+ $this->setFunction('OnShowSummary', $javascript);
+ }
+
+ /**
+ * @return string javascript code for client-side OnShowSummary event.
+ */
+ public function getOnShowSummary()
+ {
+ return $this->getOption('OnShowSummary');
+ }
+
+ /**
+ * Ensure the string is a valid javascript function. The code block
+ * is enclosed with "function(summary, validators){ }" block.
+ * @param string javascript code.
+ * @return string javascript function code.
+ */
+ protected function ensureFunction($javascript)
+ {
+ return "function(summary, validators){ {$javascript} }";
+ }
+}
+
+
+/**
+ * TValidationSummaryDisplayMode class.
+ * TValidationSummaryDisplayMode defines the enumerable type for the possible modes
+ * that a {@link TValidationSummary} can organize and display the collected error messages.
+ *
+ * The following enumerable values are defined:
+ * - SimpleList: the error messages are displayed as a list without any decorations.
+ * - SingleParagraph: the error messages are concatenated together into a paragraph.
+ * - BulletList: the error messages are displayed as a bulleted list.
+ * - HeaderOnly: only the HeaderText will be display.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationSummaryDisplayMode extends TEnumerable
+{
+ const SimpleList='SimpleList';
+ const SingleParagraph='SingleParagraph';
+ const BulletList='BulletList';
+ const HeaderOnly='HeaderOnly';
+}
+
+
+/**
+ * TValidationSummaryDisplay class.
+ * TValidationSummaryDisplay defines the enumerable type for the possible styles
+ * that a {@link TValidationSummary} can display the collected error messages.
+ *
+ * The following enumerable values are defined:
+ * - None: the error messages are not displayed
+ * - Dynamic: the error messages are dynamically added to display as the corresponding validators fail
+ * - Fixed: Similar to Dynamic except that the error messages physically occupy the page layout (even though they may not be visible)
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TValidationSummaryDisplayStyle extends TEnumerable
+{
+ const None='None';
+ const Dynamic='Dynamic';
+ const Fixed='Fixed';
+}
+
diff --git a/framework/Web/UI/WebControls/TWebControlAdapter.php b/framework/Web/UI/WebControls/TWebControlAdapter.php
index 68fecf1c..ad1e1642 100644
--- a/framework/Web/UI/WebControls/TWebControlAdapter.php
+++ b/framework/Web/UI/WebControls/TWebControlAdapter.php
@@ -1,71 +1,71 @@
-<?php
-/**
- * TWebControlAdapter class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TWebControlAdapter class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-/**
- * TWebControlAdapter class
- *
- * TWebControlAdapter is the base class for adapters that customize
- * rendering for the Web control to which the adapter is attached.
- * It may be used to modify the default markup or behavior for specific
- * browsers.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWebControlAdapter extends TControlAdapter
-{
- /**
- * Renders the control to which the adapter is attached.
- * It calls {@link renderBeginTag}, {@link renderContents} and
- * {@link renderEndTag} in order.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function render($writer)
- {
- $this->renderBeginTag($writer);
- $this->renderContents($writer);
- $this->renderEndTag($writer);
- }
-
- /**
- * Renders the openning tag for the attached control.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderBeginTag($writer)
- {
- $this->getControl()->renderBeginTag($writer);
- }
-
- /**
- * Renders the body contents within the attached control tag.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderContents($writer)
- {
- $this->getControl()->renderContents($writer);
- }
-
- /**
- * Renders the closing tag for the attached control.
- * Default implementation calls the attached control's corresponding method.
- * @param THtmlWriter writer for the rendering purpose
- */
- public function renderEndTag($writer)
- {
- $this->getControl()->renderEndTag($writer);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * TWebControlAdapter class
+ *
+ * TWebControlAdapter is the base class for adapters that customize
+ * rendering for the Web control to which the adapter is attached.
+ * It may be used to modify the default markup or behavior for specific
+ * browsers.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWebControlAdapter extends TControlAdapter
+{
+ /**
+ * Renders the control to which the adapter is attached.
+ * It calls {@link renderBeginTag}, {@link renderContents} and
+ * {@link renderEndTag} in order.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function render($writer)
+ {
+ $this->renderBeginTag($writer);
+ $this->renderContents($writer);
+ $this->renderEndTag($writer);
+ }
+
+ /**
+ * Renders the openning tag for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderBeginTag($writer)
+ {
+ $this->getControl()->renderBeginTag($writer);
+ }
+
+ /**
+ * Renders the body contents within the attached control tag.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderContents($writer)
+ {
+ $this->getControl()->renderContents($writer);
+ }
+
+ /**
+ * Renders the closing tag for the attached control.
+ * Default implementation calls the attached control's corresponding method.
+ * @param THtmlWriter writer for the rendering purpose
+ */
+ public function renderEndTag($writer)
+ {
+ $this->getControl()->renderEndTag($writer);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/TWizard.php b/framework/Web/UI/WebControls/TWizard.php
index 25d3a41b..b497d719 100644
--- a/framework/Web/UI/WebControls/TWizard.php
+++ b/framework/Web/UI/WebControls/TWizard.php
@@ -1,1402 +1,1402 @@
-<?php
-/**
- * TWizard and the relevant class definitions.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TWizard and the relevant class definitions.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls
- */
-
-Prado::using('System.Web.UI.WebControls.TMultiView');
-Prado::using('System.Web.UI.WebControls.TPanel');
-Prado::using('System.Web.UI.WebControls.TButton');
-Prado::using('System.Web.UI.WebControls.TLinkButton');
-Prado::using('System.Web.UI.WebControls.TImageButton');
-Prado::using('System.Web.UI.WebControls.TDataList');
-Prado::using('System.Web.UI.WebControls.TWizardNavigationButtonStyle');
-
-/**
- * Class TWizard.
- *
- * TWizard splits a large form and presents the user with a series of smaller
- * forms to complete. TWizard is analogous to the installation wizard commonly
- * used to install software in Windows.
- *
- * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via
- * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added
- * into a wizard using the following syntax,
- * <code>
- * <com:TWizard>
- * <com:TWizardStep Title="step 1">
- * content in step 1, may contain other controls
- * </com:TWizardStep>
- * <com:TWizardStep Title="step 2">
- * content in step 2, may contain other controls
- * </com:TWizardStep>
- * </com:TWizard>
- * </code>
- *
- * Each wizard step can be one of the following types:
- * - Start : the first step in the wizard.
- * - Step : the internal steps in the wizard.
- * - Finish : the last step that allows user interaction.
- * - Complete : the step that shows a summary to user (no interaction is allowed).
- * - Auto : the step type is determined by wizard automatically.
- * At any time, only one step is visible to end-users, which can be obtained
- * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by
- * {@link getActiveStepIndex ActiveStepIndex}.
- *
- * Wizard content can be customized in many ways.
- *
- * The layout of a wizard consists of four parts: header, step content, navigation
- * and side bar. Their content are affected by the following properties, respectively,
- * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}.
- * If both are present, the latter takes precedence.
- * - step: {@link getWizardSteps WizardSteps}.
- * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate},
- * {@link setStepNavigationTemplate StepNavigationTemplate},
- * {@link setFinishNavigationTemplate FinishNavigationTemplate}.
- * Default templates will be used if above templates are not set.
- * - side bar: {@link setSideBarTemplate SideBarTemplate}.
- * A default template will be used if this template is not set.
- * Its visibility is toggled by {@link setShowSideBar ShowSideBar}.
- *
- * The style of these wizard layout components can be customized via the following style properties,
- * - header: {@link getHeaderStyle HeaderStyle}.
- * - step: {@link getStepStyle StepStyle}.
- * - navigation: {@link getNavigationStyle NavigationStyle},
- * {@link getStartNextButtonStyle StartNextButtonStyle},
- * {@link getStepNextButtonStyle StepNextButtonStyle},
- * {@link getStepPreviousButtonStyle StepPreviousButtonStyle},
- * {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle},
- * {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle},
- * {@link getCancelButtonStyle CancelButtonStyle}.
- * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizard extends TWebControl implements INamingContainer
-{
- /**
- * Wizard step types.
- * @deprecated deprecated since version 3.0.4 (use TWizardStepType constants instead)
- */
- const ST_AUTO='Auto';
- const ST_START='Start';
- const ST_STEP='Step';
- const ST_FINISH='Finish';
- const ST_COMPLETE='Complete';
- /**
- * Navigation commands.
- */
- const CMD_PREVIOUS='PreviousStep';
- const CMD_NEXT='NextStep';
- const CMD_CANCEL='Cancel';
- const CMD_COMPLETE='Complete';
- const CMD_MOVETO='MoveTo';
- /**
- * Side bar button ID
- */
- const ID_SIDEBAR_BUTTON='SideBarButton';
- /**
- * Side bar data list
- */
- const ID_SIDEBAR_LIST='SideBarList';
-
- /**
- * @var TMultiView multiview that contains the wizard steps
- */
- private $_multiView=null;
- /**
- * @var mixed navigation template for the start step.
- */
- private $_startNavigationTemplate=null;
- /**
- * @var mixed navigation template for internal steps.
- */
- private $_stepNavigationTemplate=null;
- /**
- * @var mixed navigation template for the finish step.
- */
- private $_finishNavigationTemplate=null;
- /**
- * @var mixed template for wizard header.
- */
- private $_headerTemplate=null;
- /**
- * @var mixed template for the side bar.
- */
- private $_sideBarTemplate=null;
- /**
- * @var TWizardStepCollection
- */
- private $_wizardSteps=null;
- /**
- * @var TPanel container of the wizard header
- */
- private $_header;
- /**
- * @var TPanel container of the wizard step content
- */
- private $_stepContent;
- /**
- * @var TPanel container of the wizard side bar
- */
- private $_sideBar;
- /**
- * @var TPanel navigation panel
- */
- private $_navigation;
- /**
- * @var TWizardNavigationContainer container of the start navigation
- */
- private $_startNavigation;
- /**
- * @var TWizardNavigationContainer container of the step navigation
- */
- private $_stepNavigation;
- /**
- * @var TWizardNavigationContainer container of the finish navigation
- */
- private $_finishNavigation;
- /**
- * @var boolean whether ActiveStepIndex was already set
- */
- private $_activeStepIndexSet=false;
- /**
- * @var TDataList side bar data list.
- */
- private $_sideBarDataList;
- /**
- * @var boolean whether navigation should be cancelled (a status set in OnSideBarButtonClick)
- */
- private $_cancelNavigation=false;
-
- /**
- * @return string tag name for the wizard
- */
- protected function getTagName()
- {
- return 'div';
- }
-
- /**
- * Adds {@link TWizardStep} objects into step collection.
- * This method overrides the parent implementation and is
- * invoked when template is being instantiated.
- * @param mixed object instantiated in template
- */
- public function addParsedObject($object)
- {
- if($object instanceof TWizardStep)
- $this->getWizardSteps()->add($object);
- }
-
- /**
- * @return TWizardStep the currently active wizard step
- */
- public function getActiveStep()
- {
- return $this->getMultiView()->getActiveView();
- }
-
- /**
- * @param TWizardStep step to be activated
- * @throws TInvalidOperationException if the step is not in the wizard step collection
- */
- public function setActiveStep($step)
- {
- if(($index=$this->getWizardSteps()->indexOf($step))<0)
- throw new TInvalidOperationException('wizard_step_invalid');
- $this->setActiveStepIndex($index);
- }
-
- /**
- * @return integer the zero-based index of the active wizard step
- */
- public function getActiveStepIndex()
- {
- return $this->getMultiView()->getActiveViewIndex();
- }
-
- /**
- * @param integer the zero-based index of the wizard step to be activated
- */
- public function setActiveStepIndex($value)
- {
- $value=TPropertyValue::ensureInteger($value);
- $multiView=$this->getMultiView();
- if($multiView->getActiveViewIndex()!==$value)
- {
- $multiView->setActiveViewIndex($value);
- $this->_activeStepIndexSet=true;
- if($this->_sideBarDataList!==null && $this->getSideBarTemplate()!==null)
- {
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
- }
-
- /**
- * @return TWizardStepCollection collection of wizard steps
- */
- public function getWizardSteps()
- {
- if($this->_wizardSteps===null)
- $this->_wizardSteps=new TWizardStepCollection($this);
- return $this->_wizardSteps;
- }
-
- /**
- * @return boolean whether to display a cancel button in each wizard step. Defaults to false.
- */
- public function getShowCancelButton()
- {
- return $this->getViewState('ShowCancelButton',false);
- }
-
- /**
- * @param boolean whether to display a cancel button in each wizard step.
- */
- public function setShowCancelButton($value)
- {
- $this->setViewState('ShowCancelButton',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether to display a side bar that contains links to wizard steps. Defaults to true.
- */
- public function getShowSideBar()
- {
- return $this->getViewState('ShowSideBar',true);
- }
-
- /**
- * @param boolean whether to display a side bar that contains links to wizard steps.
- */
- public function setShowSideBar($value)
- {
- $this->setViewState('ShowSideBar',TPropertyValue::ensureBoolean($value),true);
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for the start step. Defaults to null.
- */
- public function getStartNavigationTemplate()
- {
- return $this->_startNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for the start step.
- */
- public function setStartNavigationTemplate($value)
- {
- $this->_startNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for internal steps. Defaults to null.
- */
- public function getStepNavigationTemplate()
- {
- return $this->_stepNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for internal steps.
- */
- public function setStepNavigationTemplate($value)
- {
- $this->_stepNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate navigation template for the finish step. Defaults to null.
- */
- public function getFinishNavigationTemplate()
- {
- return $this->_finishNavigationTemplate;
- }
-
- /**
- * @param ITemplate navigation template for the finish step.
- */
- public function setFinishNavigationTemplate($value)
- {
- $this->_finishNavigationTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate template for wizard header. Defaults to null.
- */
- public function getHeaderTemplate()
- {
- return $this->_headerTemplate;
- }
-
- /**
- * @param ITemplate template for wizard header.
- */
- public function setHeaderTemplate($value)
- {
- $this->_headerTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return ITemplate template for the side bar. Defaults to null.
- */
- public function getSideBarTemplate()
- {
- return $this->_sideBarTemplate;
- }
-
- /**
- * @param ITemplate template for the side bar.
- */
- public function setSideBarTemplate($value)
- {
- $this->_sideBarTemplate=$value;
- $this->requiresControlsRecreation();
- }
-
- /**
- * @return string header text. Defaults to ''.
- */
- public function getHeaderText()
- {
- return $this->getViewState('HeaderText','');
- }
-
- /**
- * @param string header text.
- */
- public function setHeaderText($value)
- {
- $this->setViewState('HeaderText',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL that the browser will be redirected to if the cancel button in the
- * wizard is clicked. Defaults to ''.
- */
- public function getCancelDestinationUrl()
- {
- return $this->getViewState('CancelDestinationUrl','');
- }
-
- /**
- * @param string the URL that the browser will be redirected to if the cancel button in the
- * wizard is clicked.
- */
- public function setCancelDestinationUrl($value)
- {
- $this->setViewState('CancelDestinationUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return string the URL that the browser will be redirected to if the wizard finishes.
- * Defaults to ''.
- */
- public function getFinishDestinationUrl()
- {
- return $this->getViewState('FinishDestinationUrl','');
- }
-
- /**
- * @param string the URL that the browser will be redirected to if the wizard finishes.
- */
- public function setFinishDestinationUrl($value)
- {
- $this->setViewState('FinishDestinationUrl',TPropertyValue::ensureString($value),'');
- }
-
- /**
- * @return TStyle the style for the buttons displayed in the side bar.
- */
- public function getSideBarButtonStyle()
- {
- if(($style=$this->getViewState('SideBarButtonStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('SideBarButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TStyle the style common for all navigation buttons.
- */
- public function getNavigationButtonStyle()
- {
- if(($style=$this->getViewState('NavigationButtonStyle',null))===null)
- {
- $style=new TStyle;
- $this->setViewState('NavigationButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step.
- */
- public function getStartNextButtonStyle()
- {
- if(($style=$this->getViewState('StartNextButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Next');
- $this->setViewState('StartNextButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step.
- */
- public function getStepNextButtonStyle()
- {
- if(($style=$this->getViewState('StepNextButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Next');
- $this->setViewState('StepNextButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
- */
- public function getStepPreviousButtonStyle()
- {
- if(($style=$this->getViewState('StepPreviousButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Previous');
- $this->setViewState('StepPreviousButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step.
- */
- public function getFinishCompleteButtonStyle()
- {
- if(($style=$this->getViewState('FinishCompleteButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Complete');
- $this->setViewState('FinishCompleteButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
- */
- public function getFinishPreviousButtonStyle()
- {
- if(($style=$this->getViewState('FinishPreviousButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Previous');
- $this->setViewState('FinishPreviousButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TWizardNavigationButtonStyle the style for the cancel button
- */
- public function getCancelButtonStyle()
- {
- if(($style=$this->getViewState('CancelButtonStyle',null))===null)
- {
- $style=new TWizardNavigationButtonStyle;
- $style->setButtonText('Cancel');
- $this->setViewState('CancelButtonStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the side bar.
- */
- public function getSideBarStyle()
- {
- if(($style=$this->getViewState('SideBarStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('SideBarStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the header.
- */
- public function getHeaderStyle()
- {
- if(($style=$this->getViewState('HeaderStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('HeaderStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for each internal wizard step.
- */
- public function getStepStyle()
- {
- if(($style=$this->getViewState('StepStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('StepStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return TPanelStyle the style for the navigation panel.
- */
- public function getNavigationStyle()
- {
- if(($style=$this->getViewState('NavigationStyle',null))===null)
- {
- $style=new TPanelStyle;
- $this->setViewState('NavigationStyle',$style,null);
- }
- return $style;
- }
-
- /**
- * @return boolean whether to use default layout to arrange side bar and the rest wizard components. Defaults to true.
- */
- public function getUseDefaultLayout()
- {
- return $this->getViewState('UseDefaultLayout',true);
- }
-
- /**
- * @param boolean whether to use default layout to arrange side bar and the rest wizard components.
- * If true, an HTML table will be used which places the side bar in the left cell
- * while the rest components in the right cell.
- */
- public function setUseDefaultLayout($value)
- {
- $this->setViewState('UseDefaultLayout',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TPanel container of the wizard header
- */
- public function getHeader()
- {
- return $this->_header;
- }
-
- /**
- * @return TPanel container of the wizard step content
- */
- public function getStepContent()
- {
- return $this->_stepContent;
- }
-
- /**
- * @return TPanel container of the wizard side bar
- */
- public function getSideBar()
- {
- return $this->_sideBar;
- }
-
- /**
- * @return TWizardNavigationContainer container of the start navigation
- */
- public function getStartNavigation()
- {
- return $this->_startNavigation;
- }
-
- /**
- * @return TWizardNavigationContainer container of the step navigation
- */
- public function getStepNavigation()
- {
- return $this->_stepNavigation;
- }
-
- /**
- * @return TWizardNavigationContainer container of the finish navigation
- */
- public function getFinishNavigation()
- {
- return $this->_finishNavigation;
- }
-
- /**
- * Raises <b>OnActiveStepChanged</b> event.
- * This event is raised when the current visible step is changed in the
- * wizard.
- * @param TEventParameter event parameter
- */
- public function onActiveStepChanged($param)
- {
- $this->raiseEvent('OnActiveStepChanged',$this,$param);
- }
-
- /**
- * Raises <b>OnCancelButtonClick</b> event.
- * This event is raised when a cancel navigation button is clicked in the
- * current active step.
- * @param TEventParameter event parameter
- */
- public function onCancelButtonClick($param)
- {
- $this->raiseEvent('OnCancelButtonClick',$this,$param);
- if(($url=$this->getCancelDestinationUrl())!=='')
- $this->getResponse()->redirect($url);
- }
-
- /**
- * Raises <b>OnCompleteButtonClick</b> event.
- * This event is raised when a finish navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onCompleteButtonClick($param)
- {
- $this->raiseEvent('OnCompleteButtonClick',$this,$param);
- if(($url=$this->getFinishDestinationUrl())!=='')
- $this->getResponse()->redirect($url);
- }
-
- /**
- * Raises <b>OnNextButtonClick</b> event.
- * This event is raised when a next navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onNextButtonClick($param)
- {
- $this->raiseEvent('OnNextButtonClick',$this,$param);
- }
-
- /**
- * Raises <b>OnPreviousButtonClick</b> event.
- * This event is raised when a previous navigation button is clicked in the
- * current active step.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onPreviousButtonClick($param)
- {
- $this->raiseEvent('OnPreviousButtonClick',$this,$param);
- }
-
- /**
- * Raises <b>OnSideBarButtonClick</b> event.
- * This event is raised when a link button in the side bar is clicked.
- * @param TWizardNavigationEventParameter event parameter
- */
- public function onSideBarButtonClick($param)
- {
- $this->raiseEvent('OnSideBarButtonClick',$this,$param);
- }
-
- /**
- * Returns the multiview that holds the wizard steps.
- * This method should only be used by control developers.
- * @return TMultiView the multiview holding wizard steps
- */
- public function getMultiView()
- {
- if($this->_multiView===null)
- {
- $this->_multiView=new TMultiView;
- $this->_multiView->setID('WizardMultiView');
- $this->_multiView->attachEventHandler('OnActiveViewChanged',array($this,'onActiveStepChanged'));
- $this->_multiView->ignoreBubbleEvents();
- }
- return $this->_multiView;
- }
-
- /**
- * Adds a wizard step to the multiview.
- * This method should only be used by control developers.
- * It is invoked when a step is added into the step collection of the wizard.
- * @param TWizardStep wizard step to be added into multiview.
- */
- public function addedWizardStep($step)
- {
- if(($wizard=$step->getWizard())!==null)
- $wizard->getWizardSteps()->remove($step);
- $step->setWizard($this);
- $this->wizardStepsChanged();
- }
-
- /**
- * Removes a wizard step from the multiview.
- * This method should only be used by control developers.
- * It is invoked when a step is removed from the step collection of the wizard.
- * @param TWizardStep wizard step to be removed from multiview.
- */
- public function removedWizardStep($step)
- {
- $step->setWizard(null);
- $this->wizardStepsChanged();
- }
-
- /**
- * Creates the child controls of the wizard.
- * This method overrides the parent implementation.
- * @param TEventParameter event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->ensureChildControls();
- if($this->getActiveStepIndex()<0 && $this->getWizardSteps()->getCount()>0)
- $this->setActiveStepIndex(0);
- }
-
- /**
- * Saves the current active step index into history.
- * This method is invoked by the framework when the control state is being saved.
- */
- public function saveState()
- {
- $index=$this->getActiveStepIndex();
- $history=$this->getHistory();
- if(!$history->getCount() || $history->peek()!==$index)
- $history->push($index);
- }
-
- /**
- * Indicates the wizard needs to recreate all child controls.
- */
- protected function requiresControlsRecreation()
- {
- if($this->getChildControlsCreated())
- $this->setChildControlsCreated(false);
- }
-
- /**
- * Renders the wizard.
- * @param THtmlWriter
- */
- public function render($writer)
- {
- $this->ensureChildControls();
- if($this->getHasControls())
- {
- if($this->getUseDefaultLayout())
- {
- $this->applyControlProperties();
- $this->renderBeginTag($writer);
- $writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n");
- $this->_sideBar->renderControl($writer);
- $writer->write("\n</td><td valign=\"top\">\n");
- $this->_header->renderControl($writer);
- $this->_stepContent->renderControl($writer);
- $this->_navigation->renderControl($writer);
- $writer->write("\n</td></tr></table>\n");
- $this->renderEndTag($writer);
- }
- else
- {
- $this->applyControlProperties();
- $this->renderBeginTag($writer);
- $this->_sideBar->renderControl($writer);
- $this->_header->renderControl($writer);
- $this->_stepContent->renderControl($writer);
- $this->_navigation->renderControl($writer);
- $this->renderEndTag($writer);
- }
- }
- }
-
- /**
- * Applies various properties to the components of wizard
- */
- protected function applyControlProperties()
- {
- $this->applyHeaderProperties();
- $this->applySideBarProperties();
- $this->applyStepContentProperties();
- $this->applyNavigationProperties();
- }
-
- /**
- * Applies properties to the wizard header
- */
- protected function applyHeaderProperties()
- {
- if(($style=$this->getViewState('HeaderStyle',null))!==null)
- $this->_header->getStyle()->mergeWith($style);
- if($this->getHeaderTemplate()===null)
- {
- $this->_header->getControls()->clear();
- $this->_header->getControls()->add($this->getHeaderText());
- }
- }
-
- /**
- * Applies properties to the wizard sidebar
- */
- protected function applySideBarProperties()
- {
- $this->_sideBar->setVisible($this->getShowSideBar());
- if($this->_sideBarDataList!==null && $this->getShowSideBar())
- {
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- if(($style=$this->getViewState('SideBarButtonStyle',null))!==null)
- {
- foreach($this->_sideBarDataList->getItems() as $item)
- {
- if(($button=$item->findControl('SideBarButton'))!==null)
- $button->getStyle()->mergeWith($style);
- }
- }
- }
- if(($style=$this->getViewState('SideBarStyle',null))!==null)
- $this->_sideBar->getStyle()->mergeWith($style);
- }
-
- /**
- * Applies properties to the wizard step content
- */
- protected function applyStepContentProperties()
- {
- if(($style=$this->getViewState('StepStyle',null))!==null)
- $this->_stepContent->getStyle()->mergeWith($style);
- }
-
- /**
- * Apply properties to various navigation panels.
- */
- protected function applyNavigationProperties()
- {
- $wizardSteps=$this->getWizardSteps();
- $activeStep=$this->getActiveStep();
- $activeStepIndex=$this->getActiveStepIndex();
-
- if(!$this->_navigation)
- return;
- else if($activeStepIndex<0 || $activeStepIndex>=$wizardSteps->getCount())
- {
- $this->_navigation->setVisible(false);
- return;
- }
-
- // set visibility of different types of navigation panel
- $showStandard=true;
- foreach($wizardSteps as $step)
- {
- if(($step instanceof TTemplatedWizardStep) && ($container=$step->getNavigationContainer())!==null)
- {
- if($activeStep===$step)
- {
- $container->setVisible(true);
- $showStandard=false;
- }
- else
- $container->setVisible(false);
- }
- }
- $activeStepType=$this->getStepType($activeStep);
- if($activeStepType===TWizardStepType::Complete)
- {
- $this->_sideBar->setVisible(false);
- $this->_header->setVisible(false);
- }
- $this->_startNavigation->setVisible($showStandard && $activeStepType===self::ST_START);
- $this->_stepNavigation->setVisible($showStandard && $activeStepType===self::ST_STEP);
- $this->_finishNavigation->setVisible($showStandard && $activeStepType===self::ST_FINISH);
-
- if(($navigationStyle=$this->getViewState('NavigationStyle',null))!==null)
- $this->_navigation->getStyle()->mergeWith($navigationStyle);
-
- $displayCancelButton=$this->getShowCancelButton();
- $cancelButtonStyle=$this->getCancelButtonStyle();
- $buttonStyle=$this->getViewState('NavigationButtonStyle',null);
- if($buttonStyle!==null)
- $cancelButtonStyle->mergeWith($buttonStyle);
-
- // apply styles to start navigation buttons
- if(($cancelButton=$this->_startNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_startNavigation->getNextButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getStartNextButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Start)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
-
- // apply styles to finish navigation buttons
- if(($cancelButton=$this->_finishNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_finishNavigation->getPreviousButton())!==null)
- {
- $button->setVisible($this->allowNavigationToPreviousStep());
- $style=$this->getFinishPreviousButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- }
- if(($button=$this->_finishNavigation->getCompleteButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getFinishCompleteButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Finish)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
-
- // apply styles to step navigation buttons
- if(($cancelButton=$this->_stepNavigation->getCancelButton())!==null)
- {
- $cancelButton->setVisible($displayCancelButton);
- $cancelButtonStyle->apply($cancelButton);
- }
- if(($button=$this->_stepNavigation->getPreviousButton())!==null)
- {
- $button->setVisible($this->allowNavigationToPreviousStep());
- $style=$this->getStepPreviousButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- }
- if(($button=$this->_stepNavigation->getNextButton())!==null)
- {
- $button->setVisible(true);
- $style=$this->getStepNextButtonStyle();
- if($buttonStyle!==null)
- $style->mergeWith($buttonStyle);
- $style->apply($button);
- if($activeStepType===TWizardStepType::Step)
- $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
- }
- }
-
- /**
- * @return TStack history containing step indexes that were navigated before
- */
- protected function getHistory()
- {
- if(($history=$this->getControlState('History',null))===null)
- {
- $history=new TStack;
- $this->setControlState('History',$history);
- }
- return $history;
- }
-
- /**
- * Determines the type of the specified wizard step.
- * @param TWizardStep
- * @return TWizardStepType type of the step
- */
- protected function getStepType($wizardStep)
- {
- if(($type=$wizardStep->getStepType())===TWizardStepType::Auto)
- {
- $steps=$this->getWizardSteps();
- if(($index=$steps->indexOf($wizardStep))>=0)
- {
- $stepCount=$steps->getCount();
- if($stepCount===1 || ($index<$stepCount-1 && $steps->itemAt($index+1)->getStepType()===TWizardStepType::Complete))
- return TWizardStepType::Finish;
- else if($index===0)
- return TWizardStepType::Start;
- else if($index===$stepCount-1)
- return TWizardStepType::Finish;
- else
- return TWizardStepType::Step;
- }
- else
- return $type;
- }
- else
- return $type;
- }
-
- /**
- * Clears up everything within the wizard.
- */
- protected function reset()
- {
- $this->getControls()->clear();
- $this->_header=null;
- $this->_stepContent=null;
- $this->_sideBar=null;
- $this->_sideBarDataList=null;
- $this->_navigation=null;
- $this->_startNavigation=null;
- $this->_stepNavigation=null;
- $this->_finishNavigation=null;
- }
-
- /**
- * Creates child controls within the wizard
- */
- public function createChildControls()
- {
- $this->reset();
- $this->createSideBar();
- $this->createHeader();
- $this->createStepContent();
- $this->createNavigation();
-// $this->clearChildState();
- }
-
- /**
- * Creates the wizard header.
- */
- protected function createHeader()
- {
- $this->_header=new TPanel;
- if(($template=$this->getHeaderTemplate())!==null)
- $template->instantiateIn($this->_header);
- else
- $this->_header->getControls()->add($this->getHeaderText());
- $this->getControls()->add($this->_header);
- }
-
- /**
- * Creates the wizard side bar
- */
- protected function createSideBar()
- {
- if($this->getShowSideBar())
- {
- if(($template=$this->getSideBarTemplate())===null)
- $template=new TWizardSideBarTemplate;
- $this->_sideBar=new TPanel;
- $template->instantiateIn($this->_sideBar);
- $this->getControls()->add($this->_sideBar);
-
- if(($this->_sideBarDataList=$this->_sideBar->findControl(self::ID_SIDEBAR_LIST))!==null)
- {
- $this->_sideBarDataList->attachEventHandler('OnItemCommand',array($this,'dataListItemCommand'));
- $this->_sideBarDataList->attachEventHandler('OnItemDataBound',array($this,'dataListItemDataBound'));
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
- else
- {
- $this->_sideBar=new TPanel;
- $this->getControls()->add($this->_sideBar);
- }
- }
-
- /**
- * Event handler for sidebar datalist's OnItemCommand event.
- * This method is used internally by wizard. It mainly
- * sets the active step index according to the button clicked in the sidebar.
- * @param mixed sender of the event
- * @param TDataListCommandEventParameter
- */
- public function dataListItemCommand($sender,$param)
- {
- $item=$param->getItem();
- if($param->getCommandName()===self::CMD_MOVETO)
- {
- $stepIndex=$this->getActiveStepIndex();
- $newStepIndex=TPropertyValue::ensureInteger($param->getCommandParameter());
- $navParam=new TWizardNavigationEventParameter($stepIndex);
- $navParam->setNextStepIndex($newStepIndex);
-
- // if the button clicked causes validation which fails,
- // by default we will cancel navigation to the new step
- $button=$param->getCommandSource();
- if(($button instanceof IButtonControl) && $button->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
- $navParam->setCancelNavigation(true);
-
- $this->_activeStepIndexSet=false;
- $this->onSideBarButtonClick($navParam);
- $this->_cancelNavigation=$navParam->getCancelNavigation();
- if(!$this->_cancelNavigation)
- {
- if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex))
- $this->setActiveStepIndex($newStepIndex);
- }
- else
- $this->setActiveStepIndex($stepIndex);
- }
- }
-
- /**
- * Event handler for sidebar datalist's OnItemDataBound event.
- * This method is used internally by wizard. It mainly configures
- * the buttons in the sidebar datalist.
- * @param mixed sender of the event
- * @param TDataListItemEventParameter
- */
- public function dataListItemDataBound($sender,$param)
- {
- $item=$param->getItem();
- $itemType=$item->getItemType();
- if($itemType==='Item' || $itemType==='AlternatingItem' || $itemType==='SelectedItem' || $itemType==='EditItem')
- {
- if(($button=$item->findControl(self::ID_SIDEBAR_BUTTON))!==null)
- {
- $step=$item->getData();
- if(($this->getStepType($step)===TWizardStepType::Complete))
- $button->setEnabled(false);
- if(($title=$step->getTitle())!=='')
- $button->setText($title);
- else
- $button->setText($step->getID(false));
- $index=$this->getWizardSteps()->indexOf($step);
- $button->setCommandName(self::CMD_MOVETO);
- $button->setCommandParameter("$index");
- }
- }
- }
-
- /**
- * Creates wizard step content.
- */
- protected function createStepContent()
- {
- foreach($this->getWizardSteps() as $step)
- {
- if($step instanceof TTemplatedWizardStep)
- $step->ensureChildControls();
- }
- $multiView=$this->getMultiView();
- $this->_stepContent=new TPanel;
- $this->_stepContent->getControls()->add($multiView);
- $this->getControls()->add($this->_stepContent);
- if($multiView->getViews()->getCount())
- $multiView->setActiveViewIndex(0);
- }
-
- /**
- * Creates navigation panel.
- */
- protected function createNavigation()
- {
- $this->_navigation=new TPanel;
- $this->getControls()->add($this->_navigation);
- $controls=$this->_navigation->getControls();
- foreach($this->getWizardSteps() as $step)
- {
- if($step instanceof TTemplatedWizardStep)
- {
- $step->instantiateNavigationTemplate();
- if(($panel=$step->getNavigationContainer())!==null)
- $controls->add($panel);
- }
- }
- $this->_startNavigation=$this->createStartNavigation();
- $controls->add($this->_startNavigation);
- $this->_stepNavigation=$this->createStepNavigation();
- $controls->add($this->_stepNavigation);
- $this->_finishNavigation=$this->createFinishNavigation();
- $controls->add($this->_finishNavigation);
- }
-
- /**
- * Creates start navigation panel.
- */
- protected function createStartNavigation()
- {
- if(($template=$this->getStartNavigationTemplate())===null)
- $template=new TWizardStartNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Creates step navigation panel.
- */
- protected function createStepNavigation()
- {
- if(($template=$this->getStepNavigationTemplate())===null)
- $template=new TWizardStepNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Creates finish navigation panel.
- */
- protected function createFinishNavigation()
- {
- if(($template=$this->getFinishNavigationTemplate())===null)
- $template=new TWizardFinishNavigationTemplate($this);
- $navigation=new TWizardNavigationContainer;
- $template->instantiateIn($navigation);
- return $navigation;
- }
-
- /**
- * Updates the sidebar datalist if any.
- * This method is invoked when any wizard step is changed.
- */
- public function wizardStepsChanged()
- {
- if($this->_sideBarDataList!==null)
- {
- $this->_sideBarDataList->setDataSource($this->getWizardSteps());
- $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
- $this->_sideBarDataList->dataBind();
- }
- }
-
- /**
- * Determines the index of the previous step based on history.
- * @param boolean whether the first item in the history stack should be popped
- * up after calling this method.
- */
- protected function getPreviousStepIndex($popStack)
- {
- $history=$this->getHistory();
- if($history->getCount()>=0)
- {
- $activeStepIndex=$this->getActiveStepIndex();
- $previousStepIndex=-1;
- if($popStack)
- {
- $previousStepIndex=$history->pop();
- if($activeStepIndex===$previousStepIndex && $history->getCount()>0)
- $previousStepIndex=$history->pop();
- }
- else
- {
- $previousStepIndex=$history->peek();
- if($activeStepIndex===$previousStepIndex && $history->getCount()>1)
- {
- $saveIndex=$history->pop();
- $previousStepIndex=$history->peek();
- $history->push($saveIndex);
- }
- }
- return $activeStepIndex===$previousStepIndex ? -1 : $previousStepIndex;
- }
- else
- return -1;
- }
-
- /**
- * @return boolean whether navigation to the previous step is allowed
- */
- protected function allowNavigationToPreviousStep()
- {
- if(($index=$this->getPreviousStepIndex(false))!==-1)
- return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
- else
- return false;
- }
-
- /**
- * @param integer index of the step
- * @return boolean whether navigation to the specified step is allowed
- */
- protected function allowNavigationToStep($index)
- {
- if($this->getHistory()->contains($index))
- return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
- else
- return true;
- }
-
- /**
- * Handles bubbled events.
- * This method mainly translate certain command events into
- * wizard-specific events.
- * @param mixed sender of the original command event
- * @param TEventParameter event parameter
- * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter
- */
- public function bubbleEvent($sender,$param)
- {
- if($param instanceof TCommandEventParameter)
- {
- $command=$param->getCommandName();
- if(strcasecmp($command,self::CMD_CANCEL)===0)
- {
- $this->onCancelButtonClick($param);
- return true;
- }
-
- $type=$this->getStepType($this->getActiveStep());
- $index=$this->getActiveStepIndex();
- $navParam=new TWizardNavigationEventParameter($index);
- if(($sender instanceof IButtonControl) && $sender->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
- $navParam->setCancelNavigation(true);
-
- $handled=false;
- $movePrev=false;
- $this->_activeStepIndexSet=false;
-
- if(strcasecmp($command,self::CMD_NEXT)===0)
- {
- if($type!==self::ST_START && $type!==self::ST_STEP)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_NEXT);
- if($index<$this->getWizardSteps()->getCount()-1)
- $navParam->setNextStepIndex($index+1);
- $this->onNextButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_PREVIOUS)===0)
- {
- if($type!==self::ST_FINISH && $type!==self::ST_STEP)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_PREVIOUS);
- $movePrev=true;
- if(($prevIndex=$this->getPreviousStepIndex(false))>=0)
- $navParam->setNextStepIndex($prevIndex);
- $this->onPreviousButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_COMPLETE)===0)
- {
- if($type!==self::ST_FINISH)
- throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_COMPLETE);
- if($index<$this->getWizardSteps()->getCount()-1)
- $navParam->setNextStepIndex($index+1);
- $this->onCompleteButtonClick($navParam);
- $handled=true;
- }
- else if(strcasecmp($command,self::CMD_MOVETO)===0)
- {
- if($this->_cancelNavigation) // may be set in onSideBarButtonClick
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ */
+
+Prado::using('System.Web.UI.WebControls.TMultiView');
+Prado::using('System.Web.UI.WebControls.TPanel');
+Prado::using('System.Web.UI.WebControls.TButton');
+Prado::using('System.Web.UI.WebControls.TLinkButton');
+Prado::using('System.Web.UI.WebControls.TImageButton');
+Prado::using('System.Web.UI.WebControls.TDataList');
+Prado::using('System.Web.UI.WebControls.TWizardNavigationButtonStyle');
+
+/**
+ * Class TWizard.
+ *
+ * TWizard splits a large form and presents the user with a series of smaller
+ * forms to complete. TWizard is analogous to the installation wizard commonly
+ * used to install software in Windows.
+ *
+ * The smaller forms are called wizard steps ({@link TWizardStep}, which can be accessed via
+ * {@link getWizardSteps WizardSteps}. In template, wizard steps can be added
+ * into a wizard using the following syntax,
+ * <code>
+ * <com:TWizard>
+ * <com:TWizardStep Title="step 1">
+ * content in step 1, may contain other controls
+ * </com:TWizardStep>
+ * <com:TWizardStep Title="step 2">
+ * content in step 2, may contain other controls
+ * </com:TWizardStep>
+ * </com:TWizard>
+ * </code>
+ *
+ * Each wizard step can be one of the following types:
+ * - Start : the first step in the wizard.
+ * - Step : the internal steps in the wizard.
+ * - Finish : the last step that allows user interaction.
+ * - Complete : the step that shows a summary to user (no interaction is allowed).
+ * - Auto : the step type is determined by wizard automatically.
+ * At any time, only one step is visible to end-users, which can be obtained
+ * by {@link getActiveStep ActiveStep}. Its index in the step collection is given by
+ * {@link getActiveStepIndex ActiveStepIndex}.
+ *
+ * Wizard content can be customized in many ways.
+ *
+ * The layout of a wizard consists of four parts: header, step content, navigation
+ * and side bar. Their content are affected by the following properties, respectively,
+ * - header: {@link setHeaderText HeaderText} and {@link setHeaderTemplate HeaderTemplate}.
+ * If both are present, the latter takes precedence.
+ * - step: {@link getWizardSteps WizardSteps}.
+ * - navigation: {@link setStartNavigationTemplate StartNavigationTemplate},
+ * {@link setStepNavigationTemplate StepNavigationTemplate},
+ * {@link setFinishNavigationTemplate FinishNavigationTemplate}.
+ * Default templates will be used if above templates are not set.
+ * - side bar: {@link setSideBarTemplate SideBarTemplate}.
+ * A default template will be used if this template is not set.
+ * Its visibility is toggled by {@link setShowSideBar ShowSideBar}.
+ *
+ * The style of these wizard layout components can be customized via the following style properties,
+ * - header: {@link getHeaderStyle HeaderStyle}.
+ * - step: {@link getStepStyle StepStyle}.
+ * - navigation: {@link getNavigationStyle NavigationStyle},
+ * {@link getStartNextButtonStyle StartNextButtonStyle},
+ * {@link getStepNextButtonStyle StepNextButtonStyle},
+ * {@link getStepPreviousButtonStyle StepPreviousButtonStyle},
+ * {@link getFinishPreviousButtonStyle FinishPreviousButtonStyle},
+ * {@link getFinishCompleteButtonStyle FinishCompleteButtonStyle},
+ * {@link getCancelButtonStyle CancelButtonStyle}.
+ * - side bar: {@link getSideBarStyle SideBarStyle} and {@link getSideBarButtonStyle SideBarButtonStyle}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizard extends TWebControl implements INamingContainer
+{
+ /**
+ * Wizard step types.
+ * @deprecated deprecated since version 3.0.4 (use TWizardStepType constants instead)
+ */
+ const ST_AUTO='Auto';
+ const ST_START='Start';
+ const ST_STEP='Step';
+ const ST_FINISH='Finish';
+ const ST_COMPLETE='Complete';
+ /**
+ * Navigation commands.
+ */
+ const CMD_PREVIOUS='PreviousStep';
+ const CMD_NEXT='NextStep';
+ const CMD_CANCEL='Cancel';
+ const CMD_COMPLETE='Complete';
+ const CMD_MOVETO='MoveTo';
+ /**
+ * Side bar button ID
+ */
+ const ID_SIDEBAR_BUTTON='SideBarButton';
+ /**
+ * Side bar data list
+ */
+ const ID_SIDEBAR_LIST='SideBarList';
+
+ /**
+ * @var TMultiView multiview that contains the wizard steps
+ */
+ private $_multiView=null;
+ /**
+ * @var mixed navigation template for the start step.
+ */
+ private $_startNavigationTemplate=null;
+ /**
+ * @var mixed navigation template for internal steps.
+ */
+ private $_stepNavigationTemplate=null;
+ /**
+ * @var mixed navigation template for the finish step.
+ */
+ private $_finishNavigationTemplate=null;
+ /**
+ * @var mixed template for wizard header.
+ */
+ private $_headerTemplate=null;
+ /**
+ * @var mixed template for the side bar.
+ */
+ private $_sideBarTemplate=null;
+ /**
+ * @var TWizardStepCollection
+ */
+ private $_wizardSteps=null;
+ /**
+ * @var TPanel container of the wizard header
+ */
+ private $_header;
+ /**
+ * @var TPanel container of the wizard step content
+ */
+ private $_stepContent;
+ /**
+ * @var TPanel container of the wizard side bar
+ */
+ private $_sideBar;
+ /**
+ * @var TPanel navigation panel
+ */
+ private $_navigation;
+ /**
+ * @var TWizardNavigationContainer container of the start navigation
+ */
+ private $_startNavigation;
+ /**
+ * @var TWizardNavigationContainer container of the step navigation
+ */
+ private $_stepNavigation;
+ /**
+ * @var TWizardNavigationContainer container of the finish navigation
+ */
+ private $_finishNavigation;
+ /**
+ * @var boolean whether ActiveStepIndex was already set
+ */
+ private $_activeStepIndexSet=false;
+ /**
+ * @var TDataList side bar data list.
+ */
+ private $_sideBarDataList;
+ /**
+ * @var boolean whether navigation should be cancelled (a status set in OnSideBarButtonClick)
+ */
+ private $_cancelNavigation=false;
+
+ /**
+ * @return string tag name for the wizard
+ */
+ protected function getTagName()
+ {
+ return 'div';
+ }
+
+ /**
+ * Adds {@link TWizardStep} objects into step collection.
+ * This method overrides the parent implementation and is
+ * invoked when template is being instantiated.
+ * @param mixed object instantiated in template
+ */
+ public function addParsedObject($object)
+ {
+ if($object instanceof TWizardStep)
+ $this->getWizardSteps()->add($object);
+ }
+
+ /**
+ * @return TWizardStep the currently active wizard step
+ */
+ public function getActiveStep()
+ {
+ return $this->getMultiView()->getActiveView();
+ }
+
+ /**
+ * @param TWizardStep step to be activated
+ * @throws TInvalidOperationException if the step is not in the wizard step collection
+ */
+ public function setActiveStep($step)
+ {
+ if(($index=$this->getWizardSteps()->indexOf($step))<0)
+ throw new TInvalidOperationException('wizard_step_invalid');
+ $this->setActiveStepIndex($index);
+ }
+
+ /**
+ * @return integer the zero-based index of the active wizard step
+ */
+ public function getActiveStepIndex()
+ {
+ return $this->getMultiView()->getActiveViewIndex();
+ }
+
+ /**
+ * @param integer the zero-based index of the wizard step to be activated
+ */
+ public function setActiveStepIndex($value)
+ {
+ $value=TPropertyValue::ensureInteger($value);
+ $multiView=$this->getMultiView();
+ if($multiView->getActiveViewIndex()!==$value)
+ {
+ $multiView->setActiveViewIndex($value);
+ $this->_activeStepIndexSet=true;
+ if($this->_sideBarDataList!==null && $this->getSideBarTemplate()!==null)
+ {
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+ }
+
+ /**
+ * @return TWizardStepCollection collection of wizard steps
+ */
+ public function getWizardSteps()
+ {
+ if($this->_wizardSteps===null)
+ $this->_wizardSteps=new TWizardStepCollection($this);
+ return $this->_wizardSteps;
+ }
+
+ /**
+ * @return boolean whether to display a cancel button in each wizard step. Defaults to false.
+ */
+ public function getShowCancelButton()
+ {
+ return $this->getViewState('ShowCancelButton',false);
+ }
+
+ /**
+ * @param boolean whether to display a cancel button in each wizard step.
+ */
+ public function setShowCancelButton($value)
+ {
+ $this->setViewState('ShowCancelButton',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether to display a side bar that contains links to wizard steps. Defaults to true.
+ */
+ public function getShowSideBar()
+ {
+ return $this->getViewState('ShowSideBar',true);
+ }
+
+ /**
+ * @param boolean whether to display a side bar that contains links to wizard steps.
+ */
+ public function setShowSideBar($value)
+ {
+ $this->setViewState('ShowSideBar',TPropertyValue::ensureBoolean($value),true);
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate navigation template for the start step. Defaults to null.
+ */
+ public function getStartNavigationTemplate()
+ {
+ return $this->_startNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for the start step.
+ */
+ public function setStartNavigationTemplate($value)
+ {
+ $this->_startNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate navigation template for internal steps. Defaults to null.
+ */
+ public function getStepNavigationTemplate()
+ {
+ return $this->_stepNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for internal steps.
+ */
+ public function setStepNavigationTemplate($value)
+ {
+ $this->_stepNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate navigation template for the finish step. Defaults to null.
+ */
+ public function getFinishNavigationTemplate()
+ {
+ return $this->_finishNavigationTemplate;
+ }
+
+ /**
+ * @param ITemplate navigation template for the finish step.
+ */
+ public function setFinishNavigationTemplate($value)
+ {
+ $this->_finishNavigationTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate template for wizard header. Defaults to null.
+ */
+ public function getHeaderTemplate()
+ {
+ return $this->_headerTemplate;
+ }
+
+ /**
+ * @param ITemplate template for wizard header.
+ */
+ public function setHeaderTemplate($value)
+ {
+ $this->_headerTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return ITemplate template for the side bar. Defaults to null.
+ */
+ public function getSideBarTemplate()
+ {
+ return $this->_sideBarTemplate;
+ }
+
+ /**
+ * @param ITemplate template for the side bar.
+ */
+ public function setSideBarTemplate($value)
+ {
+ $this->_sideBarTemplate=$value;
+ $this->requiresControlsRecreation();
+ }
+
+ /**
+ * @return string header text. Defaults to ''.
+ */
+ public function getHeaderText()
+ {
+ return $this->getViewState('HeaderText','');
+ }
+
+ /**
+ * @param string header text.
+ */
+ public function setHeaderText($value)
+ {
+ $this->setViewState('HeaderText',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL that the browser will be redirected to if the cancel button in the
+ * wizard is clicked. Defaults to ''.
+ */
+ public function getCancelDestinationUrl()
+ {
+ return $this->getViewState('CancelDestinationUrl','');
+ }
+
+ /**
+ * @param string the URL that the browser will be redirected to if the cancel button in the
+ * wizard is clicked.
+ */
+ public function setCancelDestinationUrl($value)
+ {
+ $this->setViewState('CancelDestinationUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return string the URL that the browser will be redirected to if the wizard finishes.
+ * Defaults to ''.
+ */
+ public function getFinishDestinationUrl()
+ {
+ return $this->getViewState('FinishDestinationUrl','');
+ }
+
+ /**
+ * @param string the URL that the browser will be redirected to if the wizard finishes.
+ */
+ public function setFinishDestinationUrl($value)
+ {
+ $this->setViewState('FinishDestinationUrl',TPropertyValue::ensureString($value),'');
+ }
+
+ /**
+ * @return TStyle the style for the buttons displayed in the side bar.
+ */
+ public function getSideBarButtonStyle()
+ {
+ if(($style=$this->getViewState('SideBarButtonStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('SideBarButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TStyle the style common for all navigation buttons.
+ */
+ public function getNavigationButtonStyle()
+ {
+ if(($style=$this->getViewState('NavigationButtonStyle',null))===null)
+ {
+ $style=new TStyle;
+ $this->setViewState('NavigationButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the next button in the start wizard step.
+ */
+ public function getStartNextButtonStyle()
+ {
+ if(($style=$this->getViewState('StartNextButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Next');
+ $this->setViewState('StartNextButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the next button in each internal wizard step.
+ */
+ public function getStepNextButtonStyle()
+ {
+ if(($style=$this->getViewState('StepNextButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Next');
+ $this->setViewState('StepNextButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
+ */
+ public function getStepPreviousButtonStyle()
+ {
+ if(($style=$this->getViewState('StepPreviousButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Previous');
+ $this->setViewState('StepPreviousButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the complete button in the finish wizard step.
+ */
+ public function getFinishCompleteButtonStyle()
+ {
+ if(($style=$this->getViewState('FinishCompleteButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Complete');
+ $this->setViewState('FinishCompleteButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the previous button in the start wizard step.
+ */
+ public function getFinishPreviousButtonStyle()
+ {
+ if(($style=$this->getViewState('FinishPreviousButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Previous');
+ $this->setViewState('FinishPreviousButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TWizardNavigationButtonStyle the style for the cancel button
+ */
+ public function getCancelButtonStyle()
+ {
+ if(($style=$this->getViewState('CancelButtonStyle',null))===null)
+ {
+ $style=new TWizardNavigationButtonStyle;
+ $style->setButtonText('Cancel');
+ $this->setViewState('CancelButtonStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the side bar.
+ */
+ public function getSideBarStyle()
+ {
+ if(($style=$this->getViewState('SideBarStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('SideBarStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the header.
+ */
+ public function getHeaderStyle()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('HeaderStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for each internal wizard step.
+ */
+ public function getStepStyle()
+ {
+ if(($style=$this->getViewState('StepStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('StepStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return TPanelStyle the style for the navigation panel.
+ */
+ public function getNavigationStyle()
+ {
+ if(($style=$this->getViewState('NavigationStyle',null))===null)
+ {
+ $style=new TPanelStyle;
+ $this->setViewState('NavigationStyle',$style,null);
+ }
+ return $style;
+ }
+
+ /**
+ * @return boolean whether to use default layout to arrange side bar and the rest wizard components. Defaults to true.
+ */
+ public function getUseDefaultLayout()
+ {
+ return $this->getViewState('UseDefaultLayout',true);
+ }
+
+ /**
+ * @param boolean whether to use default layout to arrange side bar and the rest wizard components.
+ * If true, an HTML table will be used which places the side bar in the left cell
+ * while the rest components in the right cell.
+ */
+ public function setUseDefaultLayout($value)
+ {
+ $this->setViewState('UseDefaultLayout',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TPanel container of the wizard header
+ */
+ public function getHeader()
+ {
+ return $this->_header;
+ }
+
+ /**
+ * @return TPanel container of the wizard step content
+ */
+ public function getStepContent()
+ {
+ return $this->_stepContent;
+ }
+
+ /**
+ * @return TPanel container of the wizard side bar
+ */
+ public function getSideBar()
+ {
+ return $this->_sideBar;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the start navigation
+ */
+ public function getStartNavigation()
+ {
+ return $this->_startNavigation;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the step navigation
+ */
+ public function getStepNavigation()
+ {
+ return $this->_stepNavigation;
+ }
+
+ /**
+ * @return TWizardNavigationContainer container of the finish navigation
+ */
+ public function getFinishNavigation()
+ {
+ return $this->_finishNavigation;
+ }
+
+ /**
+ * Raises <b>OnActiveStepChanged</b> event.
+ * This event is raised when the current visible step is changed in the
+ * wizard.
+ * @param TEventParameter event parameter
+ */
+ public function onActiveStepChanged($param)
+ {
+ $this->raiseEvent('OnActiveStepChanged',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnCancelButtonClick</b> event.
+ * This event is raised when a cancel navigation button is clicked in the
+ * current active step.
+ * @param TEventParameter event parameter
+ */
+ public function onCancelButtonClick($param)
+ {
+ $this->raiseEvent('OnCancelButtonClick',$this,$param);
+ if(($url=$this->getCancelDestinationUrl())!=='')
+ $this->getResponse()->redirect($url);
+ }
+
+ /**
+ * Raises <b>OnCompleteButtonClick</b> event.
+ * This event is raised when a finish navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onCompleteButtonClick($param)
+ {
+ $this->raiseEvent('OnCompleteButtonClick',$this,$param);
+ if(($url=$this->getFinishDestinationUrl())!=='')
+ $this->getResponse()->redirect($url);
+ }
+
+ /**
+ * Raises <b>OnNextButtonClick</b> event.
+ * This event is raised when a next navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onNextButtonClick($param)
+ {
+ $this->raiseEvent('OnNextButtonClick',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnPreviousButtonClick</b> event.
+ * This event is raised when a previous navigation button is clicked in the
+ * current active step.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onPreviousButtonClick($param)
+ {
+ $this->raiseEvent('OnPreviousButtonClick',$this,$param);
+ }
+
+ /**
+ * Raises <b>OnSideBarButtonClick</b> event.
+ * This event is raised when a link button in the side bar is clicked.
+ * @param TWizardNavigationEventParameter event parameter
+ */
+ public function onSideBarButtonClick($param)
+ {
+ $this->raiseEvent('OnSideBarButtonClick',$this,$param);
+ }
+
+ /**
+ * Returns the multiview that holds the wizard steps.
+ * This method should only be used by control developers.
+ * @return TMultiView the multiview holding wizard steps
+ */
+ public function getMultiView()
+ {
+ if($this->_multiView===null)
+ {
+ $this->_multiView=new TMultiView;
+ $this->_multiView->setID('WizardMultiView');
+ $this->_multiView->attachEventHandler('OnActiveViewChanged',array($this,'onActiveStepChanged'));
+ $this->_multiView->ignoreBubbleEvents();
+ }
+ return $this->_multiView;
+ }
+
+ /**
+ * Adds a wizard step to the multiview.
+ * This method should only be used by control developers.
+ * It is invoked when a step is added into the step collection of the wizard.
+ * @param TWizardStep wizard step to be added into multiview.
+ */
+ public function addedWizardStep($step)
+ {
+ if(($wizard=$step->getWizard())!==null)
+ $wizard->getWizardSteps()->remove($step);
+ $step->setWizard($this);
+ $this->wizardStepsChanged();
+ }
+
+ /**
+ * Removes a wizard step from the multiview.
+ * This method should only be used by control developers.
+ * It is invoked when a step is removed from the step collection of the wizard.
+ * @param TWizardStep wizard step to be removed from multiview.
+ */
+ public function removedWizardStep($step)
+ {
+ $step->setWizard(null);
+ $this->wizardStepsChanged();
+ }
+
+ /**
+ * Creates the child controls of the wizard.
+ * This method overrides the parent implementation.
+ * @param TEventParameter event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->ensureChildControls();
+ if($this->getActiveStepIndex()<0 && $this->getWizardSteps()->getCount()>0)
+ $this->setActiveStepIndex(0);
+ }
+
+ /**
+ * Saves the current active step index into history.
+ * This method is invoked by the framework when the control state is being saved.
+ */
+ public function saveState()
+ {
+ $index=$this->getActiveStepIndex();
+ $history=$this->getHistory();
+ if(!$history->getCount() || $history->peek()!==$index)
+ $history->push($index);
+ }
+
+ /**
+ * Indicates the wizard needs to recreate all child controls.
+ */
+ protected function requiresControlsRecreation()
+ {
+ if($this->getChildControlsCreated())
+ $this->setChildControlsCreated(false);
+ }
+
+ /**
+ * Renders the wizard.
+ * @param THtmlWriter
+ */
+ public function render($writer)
+ {
+ $this->ensureChildControls();
+ if($this->getHasControls())
+ {
+ if($this->getUseDefaultLayout())
+ {
+ $this->applyControlProperties();
+ $this->renderBeginTag($writer);
+ $writer->write("\n<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" height=\"100%\" width=\"100%\">\n<tr><td width=\"1\" valign=\"top\">\n");
+ $this->_sideBar->renderControl($writer);
+ $writer->write("\n</td><td valign=\"top\">\n");
+ $this->_header->renderControl($writer);
+ $this->_stepContent->renderControl($writer);
+ $this->_navigation->renderControl($writer);
+ $writer->write("\n</td></tr></table>\n");
+ $this->renderEndTag($writer);
+ }
+ else
+ {
+ $this->applyControlProperties();
+ $this->renderBeginTag($writer);
+ $this->_sideBar->renderControl($writer);
+ $this->_header->renderControl($writer);
+ $this->_stepContent->renderControl($writer);
+ $this->_navigation->renderControl($writer);
+ $this->renderEndTag($writer);
+ }
+ }
+ }
+
+ /**
+ * Applies various properties to the components of wizard
+ */
+ protected function applyControlProperties()
+ {
+ $this->applyHeaderProperties();
+ $this->applySideBarProperties();
+ $this->applyStepContentProperties();
+ $this->applyNavigationProperties();
+ }
+
+ /**
+ * Applies properties to the wizard header
+ */
+ protected function applyHeaderProperties()
+ {
+ if(($style=$this->getViewState('HeaderStyle',null))!==null)
+ $this->_header->getStyle()->mergeWith($style);
+ if($this->getHeaderTemplate()===null)
+ {
+ $this->_header->getControls()->clear();
+ $this->_header->getControls()->add($this->getHeaderText());
+ }
+ }
+
+ /**
+ * Applies properties to the wizard sidebar
+ */
+ protected function applySideBarProperties()
+ {
+ $this->_sideBar->setVisible($this->getShowSideBar());
+ if($this->_sideBarDataList!==null && $this->getShowSideBar())
+ {
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ if(($style=$this->getViewState('SideBarButtonStyle',null))!==null)
+ {
+ foreach($this->_sideBarDataList->getItems() as $item)
+ {
+ if(($button=$item->findControl('SideBarButton'))!==null)
+ $button->getStyle()->mergeWith($style);
+ }
+ }
+ }
+ if(($style=$this->getViewState('SideBarStyle',null))!==null)
+ $this->_sideBar->getStyle()->mergeWith($style);
+ }
+
+ /**
+ * Applies properties to the wizard step content
+ */
+ protected function applyStepContentProperties()
+ {
+ if(($style=$this->getViewState('StepStyle',null))!==null)
+ $this->_stepContent->getStyle()->mergeWith($style);
+ }
+
+ /**
+ * Apply properties to various navigation panels.
+ */
+ protected function applyNavigationProperties()
+ {
+ $wizardSteps=$this->getWizardSteps();
+ $activeStep=$this->getActiveStep();
+ $activeStepIndex=$this->getActiveStepIndex();
+
+ if(!$this->_navigation)
+ return;
+ else if($activeStepIndex<0 || $activeStepIndex>=$wizardSteps->getCount())
+ {
+ $this->_navigation->setVisible(false);
+ return;
+ }
+
+ // set visibility of different types of navigation panel
+ $showStandard=true;
+ foreach($wizardSteps as $step)
+ {
+ if(($step instanceof TTemplatedWizardStep) && ($container=$step->getNavigationContainer())!==null)
+ {
+ if($activeStep===$step)
+ {
+ $container->setVisible(true);
+ $showStandard=false;
+ }
+ else
+ $container->setVisible(false);
+ }
+ }
+ $activeStepType=$this->getStepType($activeStep);
+ if($activeStepType===TWizardStepType::Complete)
+ {
+ $this->_sideBar->setVisible(false);
+ $this->_header->setVisible(false);
+ }
+ $this->_startNavigation->setVisible($showStandard && $activeStepType===self::ST_START);
+ $this->_stepNavigation->setVisible($showStandard && $activeStepType===self::ST_STEP);
+ $this->_finishNavigation->setVisible($showStandard && $activeStepType===self::ST_FINISH);
+
+ if(($navigationStyle=$this->getViewState('NavigationStyle',null))!==null)
+ $this->_navigation->getStyle()->mergeWith($navigationStyle);
+
+ $displayCancelButton=$this->getShowCancelButton();
+ $cancelButtonStyle=$this->getCancelButtonStyle();
+ $buttonStyle=$this->getViewState('NavigationButtonStyle',null);
+ if($buttonStyle!==null)
+ $cancelButtonStyle->mergeWith($buttonStyle);
+
+ // apply styles to start navigation buttons
+ if(($cancelButton=$this->_startNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_startNavigation->getNextButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getStartNextButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Start)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+
+ // apply styles to finish navigation buttons
+ if(($cancelButton=$this->_finishNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_finishNavigation->getPreviousButton())!==null)
+ {
+ $button->setVisible($this->allowNavigationToPreviousStep());
+ $style=$this->getFinishPreviousButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ }
+ if(($button=$this->_finishNavigation->getCompleteButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getFinishCompleteButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Finish)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+
+ // apply styles to step navigation buttons
+ if(($cancelButton=$this->_stepNavigation->getCancelButton())!==null)
+ {
+ $cancelButton->setVisible($displayCancelButton);
+ $cancelButtonStyle->apply($cancelButton);
+ }
+ if(($button=$this->_stepNavigation->getPreviousButton())!==null)
+ {
+ $button->setVisible($this->allowNavigationToPreviousStep());
+ $style=$this->getStepPreviousButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ }
+ if(($button=$this->_stepNavigation->getNextButton())!==null)
+ {
+ $button->setVisible(true);
+ $style=$this->getStepNextButtonStyle();
+ if($buttonStyle!==null)
+ $style->mergeWith($buttonStyle);
+ $style->apply($button);
+ if($activeStepType===TWizardStepType::Step)
+ $this->getPage()->getClientScript()->registerDefaultButton($this, $button);
+ }
+ }
+
+ /**
+ * @return TStack history containing step indexes that were navigated before
+ */
+ protected function getHistory()
+ {
+ if(($history=$this->getControlState('History',null))===null)
+ {
+ $history=new TStack;
+ $this->setControlState('History',$history);
+ }
+ return $history;
+ }
+
+ /**
+ * Determines the type of the specified wizard step.
+ * @param TWizardStep
+ * @return TWizardStepType type of the step
+ */
+ protected function getStepType($wizardStep)
+ {
+ if(($type=$wizardStep->getStepType())===TWizardStepType::Auto)
+ {
+ $steps=$this->getWizardSteps();
+ if(($index=$steps->indexOf($wizardStep))>=0)
+ {
+ $stepCount=$steps->getCount();
+ if($stepCount===1 || ($index<$stepCount-1 && $steps->itemAt($index+1)->getStepType()===TWizardStepType::Complete))
+ return TWizardStepType::Finish;
+ else if($index===0)
+ return TWizardStepType::Start;
+ else if($index===$stepCount-1)
+ return TWizardStepType::Finish;
+ else
+ return TWizardStepType::Step;
+ }
+ else
+ return $type;
+ }
+ else
+ return $type;
+ }
+
+ /**
+ * Clears up everything within the wizard.
+ */
+ protected function reset()
+ {
+ $this->getControls()->clear();
+ $this->_header=null;
+ $this->_stepContent=null;
+ $this->_sideBar=null;
+ $this->_sideBarDataList=null;
+ $this->_navigation=null;
+ $this->_startNavigation=null;
+ $this->_stepNavigation=null;
+ $this->_finishNavigation=null;
+ }
+
+ /**
+ * Creates child controls within the wizard
+ */
+ public function createChildControls()
+ {
+ $this->reset();
+ $this->createSideBar();
+ $this->createHeader();
+ $this->createStepContent();
+ $this->createNavigation();
+// $this->clearChildState();
+ }
+
+ /**
+ * Creates the wizard header.
+ */
+ protected function createHeader()
+ {
+ $this->_header=new TPanel;
+ if(($template=$this->getHeaderTemplate())!==null)
+ $template->instantiateIn($this->_header);
+ else
+ $this->_header->getControls()->add($this->getHeaderText());
+ $this->getControls()->add($this->_header);
+ }
+
+ /**
+ * Creates the wizard side bar
+ */
+ protected function createSideBar()
+ {
+ if($this->getShowSideBar())
+ {
+ if(($template=$this->getSideBarTemplate())===null)
+ $template=new TWizardSideBarTemplate;
+ $this->_sideBar=new TPanel;
+ $template->instantiateIn($this->_sideBar);
+ $this->getControls()->add($this->_sideBar);
+
+ if(($this->_sideBarDataList=$this->_sideBar->findControl(self::ID_SIDEBAR_LIST))!==null)
+ {
+ $this->_sideBarDataList->attachEventHandler('OnItemCommand',array($this,'dataListItemCommand'));
+ $this->_sideBarDataList->attachEventHandler('OnItemDataBound',array($this,'dataListItemDataBound'));
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+ else
+ {
+ $this->_sideBar=new TPanel;
+ $this->getControls()->add($this->_sideBar);
+ }
+ }
+
+ /**
+ * Event handler for sidebar datalist's OnItemCommand event.
+ * This method is used internally by wizard. It mainly
+ * sets the active step index according to the button clicked in the sidebar.
+ * @param mixed sender of the event
+ * @param TDataListCommandEventParameter
+ */
+ public function dataListItemCommand($sender,$param)
+ {
+ $item=$param->getItem();
+ if($param->getCommandName()===self::CMD_MOVETO)
+ {
+ $stepIndex=$this->getActiveStepIndex();
+ $newStepIndex=TPropertyValue::ensureInteger($param->getCommandParameter());
+ $navParam=new TWizardNavigationEventParameter($stepIndex);
+ $navParam->setNextStepIndex($newStepIndex);
+
+ // if the button clicked causes validation which fails,
+ // by default we will cancel navigation to the new step
+ $button=$param->getCommandSource();
+ if(($button instanceof IButtonControl) && $button->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
+ $navParam->setCancelNavigation(true);
+
+ $this->_activeStepIndexSet=false;
+ $this->onSideBarButtonClick($navParam);
+ $this->_cancelNavigation=$navParam->getCancelNavigation();
+ if(!$this->_cancelNavigation)
+ {
+ if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($newStepIndex))
+ $this->setActiveStepIndex($newStepIndex);
+ }
+ else
+ $this->setActiveStepIndex($stepIndex);
+ }
+ }
+
+ /**
+ * Event handler for sidebar datalist's OnItemDataBound event.
+ * This method is used internally by wizard. It mainly configures
+ * the buttons in the sidebar datalist.
+ * @param mixed sender of the event
+ * @param TDataListItemEventParameter
+ */
+ public function dataListItemDataBound($sender,$param)
+ {
+ $item=$param->getItem();
+ $itemType=$item->getItemType();
+ if($itemType==='Item' || $itemType==='AlternatingItem' || $itemType==='SelectedItem' || $itemType==='EditItem')
+ {
+ if(($button=$item->findControl(self::ID_SIDEBAR_BUTTON))!==null)
+ {
+ $step=$item->getData();
+ if(($this->getStepType($step)===TWizardStepType::Complete))
+ $button->setEnabled(false);
+ if(($title=$step->getTitle())!=='')
+ $button->setText($title);
+ else
+ $button->setText($step->getID(false));
+ $index=$this->getWizardSteps()->indexOf($step);
+ $button->setCommandName(self::CMD_MOVETO);
+ $button->setCommandParameter("$index");
+ }
+ }
+ }
+
+ /**
+ * Creates wizard step content.
+ */
+ protected function createStepContent()
+ {
+ foreach($this->getWizardSteps() as $step)
+ {
+ if($step instanceof TTemplatedWizardStep)
+ $step->ensureChildControls();
+ }
+ $multiView=$this->getMultiView();
+ $this->_stepContent=new TPanel;
+ $this->_stepContent->getControls()->add($multiView);
+ $this->getControls()->add($this->_stepContent);
+ if($multiView->getViews()->getCount())
+ $multiView->setActiveViewIndex(0);
+ }
+
+ /**
+ * Creates navigation panel.
+ */
+ protected function createNavigation()
+ {
+ $this->_navigation=new TPanel;
+ $this->getControls()->add($this->_navigation);
+ $controls=$this->_navigation->getControls();
+ foreach($this->getWizardSteps() as $step)
+ {
+ if($step instanceof TTemplatedWizardStep)
+ {
+ $step->instantiateNavigationTemplate();
+ if(($panel=$step->getNavigationContainer())!==null)
+ $controls->add($panel);
+ }
+ }
+ $this->_startNavigation=$this->createStartNavigation();
+ $controls->add($this->_startNavigation);
+ $this->_stepNavigation=$this->createStepNavigation();
+ $controls->add($this->_stepNavigation);
+ $this->_finishNavigation=$this->createFinishNavigation();
+ $controls->add($this->_finishNavigation);
+ }
+
+ /**
+ * Creates start navigation panel.
+ */
+ protected function createStartNavigation()
+ {
+ if(($template=$this->getStartNavigationTemplate())===null)
+ $template=new TWizardStartNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Creates step navigation panel.
+ */
+ protected function createStepNavigation()
+ {
+ if(($template=$this->getStepNavigationTemplate())===null)
+ $template=new TWizardStepNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Creates finish navigation panel.
+ */
+ protected function createFinishNavigation()
+ {
+ if(($template=$this->getFinishNavigationTemplate())===null)
+ $template=new TWizardFinishNavigationTemplate($this);
+ $navigation=new TWizardNavigationContainer;
+ $template->instantiateIn($navigation);
+ return $navigation;
+ }
+
+ /**
+ * Updates the sidebar datalist if any.
+ * This method is invoked when any wizard step is changed.
+ */
+ public function wizardStepsChanged()
+ {
+ if($this->_sideBarDataList!==null)
+ {
+ $this->_sideBarDataList->setDataSource($this->getWizardSteps());
+ $this->_sideBarDataList->setSelectedItemIndex($this->getActiveStepIndex());
+ $this->_sideBarDataList->dataBind();
+ }
+ }
+
+ /**
+ * Determines the index of the previous step based on history.
+ * @param boolean whether the first item in the history stack should be popped
+ * up after calling this method.
+ */
+ protected function getPreviousStepIndex($popStack)
+ {
+ $history=$this->getHistory();
+ if($history->getCount()>=0)
+ {
+ $activeStepIndex=$this->getActiveStepIndex();
+ $previousStepIndex=-1;
+ if($popStack)
+ {
+ $previousStepIndex=$history->pop();
+ if($activeStepIndex===$previousStepIndex && $history->getCount()>0)
+ $previousStepIndex=$history->pop();
+ }
+ else
+ {
+ $previousStepIndex=$history->peek();
+ if($activeStepIndex===$previousStepIndex && $history->getCount()>1)
+ {
+ $saveIndex=$history->pop();
+ $previousStepIndex=$history->peek();
+ $history->push($saveIndex);
+ }
+ }
+ return $activeStepIndex===$previousStepIndex ? -1 : $previousStepIndex;
+ }
+ else
+ return -1;
+ }
+
+ /**
+ * @return boolean whether navigation to the previous step is allowed
+ */
+ protected function allowNavigationToPreviousStep()
+ {
+ if(($index=$this->getPreviousStepIndex(false))!==-1)
+ return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
+ else
+ return false;
+ }
+
+ /**
+ * @param integer index of the step
+ * @return boolean whether navigation to the specified step is allowed
+ */
+ protected function allowNavigationToStep($index)
+ {
+ if($this->getHistory()->contains($index))
+ return $this->getWizardSteps()->itemAt($index)->getAllowReturn();
+ else
+ return true;
+ }
+
+ /**
+ * Handles bubbled events.
+ * This method mainly translate certain command events into
+ * wizard-specific events.
+ * @param mixed sender of the original command event
+ * @param TEventParameter event parameter
+ * @throws TInvalidDataValueException if a navigation command is associated with an invalid parameter
+ */
+ public function bubbleEvent($sender,$param)
+ {
+ if($param instanceof TCommandEventParameter)
+ {
+ $command=$param->getCommandName();
+ if(strcasecmp($command,self::CMD_CANCEL)===0)
+ {
+ $this->onCancelButtonClick($param);
+ return true;
+ }
+
+ $type=$this->getStepType($this->getActiveStep());
+ $index=$this->getActiveStepIndex();
+ $navParam=new TWizardNavigationEventParameter($index);
+ if(($sender instanceof IButtonControl) && $sender->getCausesValidation() && ($page=$this->getPage())!==null && !$page->getIsValid())
+ $navParam->setCancelNavigation(true);
+
+ $handled=false;
+ $movePrev=false;
+ $this->_activeStepIndexSet=false;
+
+ if(strcasecmp($command,self::CMD_NEXT)===0)
+ {
+ if($type!==self::ST_START && $type!==self::ST_STEP)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_NEXT);
+ if($index<$this->getWizardSteps()->getCount()-1)
+ $navParam->setNextStepIndex($index+1);
+ $this->onNextButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_PREVIOUS)===0)
+ {
+ if($type!==self::ST_FINISH && $type!==self::ST_STEP)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_PREVIOUS);
+ $movePrev=true;
+ if(($prevIndex=$this->getPreviousStepIndex(false))>=0)
+ $navParam->setNextStepIndex($prevIndex);
+ $this->onPreviousButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_COMPLETE)===0)
+ {
+ if($type!==self::ST_FINISH)
+ throw new TInvalidDataValueException('wizard_command_invalid',self::CMD_COMPLETE);
+ if($index<$this->getWizardSteps()->getCount()-1)
+ $navParam->setNextStepIndex($index+1);
+ $this->onCompleteButtonClick($navParam);
+ $handled=true;
+ }
+ else if(strcasecmp($command,self::CMD_MOVETO)===0)
+ {
+ if($this->_cancelNavigation) // may be set in onSideBarButtonClick
$navParam->setCancelNavigation(true);
$requestedStep=$param->getCommandParameter();
if (!is_numeric($requestedStep))
@@ -1412,750 +1412,750 @@ class TWizard extends TWebControl implements INamingContainer
throw new TConfigurationException('wizard_step_invalid');
}
else
- $requestedIndex=TPropertyValue::ensureInteger($requestedStep);
- $navParam->setNextStepIndex($requestedIndex);
- $handled=true;
- }
-
- if($handled)
- {
- if(!$navParam->getCancelNavigation())
- {
- $nextStepIndex=$navParam->getNextStepIndex();
- if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex))
- {
- if($movePrev)
- $this->getPreviousStepIndex(true); // pop out the previous move from history
- $this->setActiveStepIndex($nextStepIndex);
- }
- }
- else
- $this->setActiveStepIndex($index);
- return true;
- }
- }
- return false;
- }
-}
-
-
-/**
- * TWizardStep class.
- *
- * TWizardStep represents a wizard step. The wizard owning the step
- * can be obtained by {@link getWizard Wizard}.
- * To specify the type of the step, set {@link setStepType StepType};
- * For step title, set {@link setTitle Title}. If a step can be re-visited,
- * set {@link setAllowReturn AllowReturn} to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStep extends TView
-{
- private $_wizard;
-
- /**
- * @return TWizard the wizard owning this step
- */
- public function getWizard()
- {
- return $this->_wizard;
- }
-
- /**
- * Sets the wizard owning this step.
- * This method is used internally by {@link TWizard}.
- * @param TWizard the wizard owning this step
- */
- public function setWizard($wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * @return string the title for this step.
- */
- public function getTitle()
- {
- return $this->getViewState('Title','');
- }
-
- /**
- * @param string the title for this step.
- */
- public function setTitle($value)
- {
- $this->setViewState('Title',$value,'');
- if($this->_wizard)
- $this->_wizard->wizardStepsChanged();
- }
-
- /**
- * @return boolean whether this step can be re-visited. Default to true.
- */
- public function getAllowReturn()
- {
- return $this->getViewState('AllowReturn',true);
- }
-
- /**
- * @param boolean whether this step can be re-visited.
- */
- public function setAllowReturn($value)
- {
- $this->setViewState('AllowReturn',TPropertyValue::ensureBoolean($value),true);
- }
-
- /**
- * @return TWizardStepType the wizard step type. Defaults to TWizardStepType::Auto.
- */
- public function getStepType()
- {
- return $this->getViewState('StepType',TWizardStepType::Auto);
- }
-
- /**
- * @param TWizardStepType the wizard step type.
- */
- public function setStepType($type)
- {
- $type=TPropertyValue::ensureEnum($type,'TWizardStepType');
- if($type!==$this->getStepType())
- {
- $this->setViewState('StepType',$type,TWizardStepType::Auto);
- if($this->_wizard)
- $this->_wizard->wizardStepsChanged();
- }
- }
-}
-
-
-/**
- * TCompleteWizardStep class.
- *
- * TCompleteWizardStep represents a wizard step of type TWizardStepType::Complete.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TCompleteWizardStep extends TWizardStep
-{
- /**
- * @return TWizardStepType the wizard step type. Always TWizardStepType::Complete.
- */
- public function getStepType()
- {
- return TWizardStepType::Complete;
- }
-
- /**
- * @param string the wizard step type.
- * @throws TInvalidOperationException whenever this method is invoked.
- */
- public function setStepType($value)
- {
- throw new TInvalidOperationException('completewizardstep_steptype_readonly');
- }
-}
-
-
-/**
- * TTemplatedWizardStep class.
- *
- * TTemplatedWizardStep represents a wizard step whose content and navigation
- * can be customized using templates. To customize the step content, specify
- * {@link setContentTemplate ContentTemplate}. To customize navigation specific
- * to the step, specify {@link setNavigationTemplate NavigationTemplate}. Note,
- * if the navigation template is not specified, default navigation will be used.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TTemplatedWizardStep extends TWizardStep implements INamingContainer
-{
- /**
- * @var ITemplate the template for displaying the navigation UI of a wizard step.
- */
- private $_navigationTemplate=null;
- /**
- * @var ITemplate the template for displaying the content within the wizard step.
- */
- private $_contentTemplate=null;
- /**
- * @var TWizardNavigationContainer
- */
- private $_navigationContainer=null;
-
- /**
- * Creates child controls.
- * This method mainly instantiates the content template, if any.
- */
- public function createChildControls()
- {
- $this->getControls()->clear();
- if($this->_contentTemplate)
- $this->_contentTemplate->instantiateIn($this);
- }
-
- /**
- * Ensures child controls are created.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- $this->ensureChildControls();
- }
-
- /**
- * @return ITemplate the template for the content of the wizard step.
- */
- public function getContentTemplate()
- {
- return $this->_contentTemplate;
- }
-
- /**
- * @param ITemplate the template for the content of the wizard step.
- */
- public function setContentTemplate($value)
- {
- $this->_contentTemplate=$value;
- }
-
- /**
- * @return ITemplate the template for displaying the navigation UI of a wizard step. Defaults to null.
- */
- public function getNavigationTemplate()
- {
- return $this->_navigationTemplate;
- }
-
- /**
- * @param ITemplate the template for displaying the navigation UI of a wizard step.
- */
- public function setNavigationTemplate($value)
- {
- $this->_navigationTemplate=$value;
- }
-
- /**
- * @return TWizardNavigationContainer the control containing the navigation.
- * It could be null if no navigation template is specified.
- */
- public function getNavigationContainer()
- {
- return $this->_navigationContainer;
- }
-
- /**
- * Instantiates the navigation template if any
- */
- public function instantiateNavigationTemplate()
- {
- if(!$this->_navigationContainer && $this->_navigationTemplate)
- {
- $this->_navigationContainer=new TWizardNavigationContainer;
- $this->_navigationTemplate->instantiateIn($this->_navigationContainer);
- }
- }
-}
-
-
-/**
- * TWizardStepCollection class.
- *
- * TWizardStepCollection represents the collection of wizard steps owned
- * by a {@link TWizard}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStepCollection extends TList
-{
- /**
- * @var TWizard
- */
- private $_wizard;
-
- /**
- * Constructor.
- * @param TWizard wizard that owns this collection
- */
- public function __construct(TWizard $wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * Inserts an item at the specified position.
- * This method overrides the parent implementation by checking if
- * the item being added is a {@link TWizardStep}.
- * @param integer the speicified position.
- * @param mixed new item
- * @throws TInvalidDataTypeException if the item being added is not TWizardStep.
- */
- public function insertAt($index,$item)
- {
- if($item instanceof TWizardStep)
- {
- parent::insertAt($index,$item);
- $this->_wizard->getMultiView()->getViews()->insertAt($index,$item);
- $this->_wizard->addedWizardStep($item);
- }
- else
- throw new TInvalidDataTypeException('wizardstepcollection_wizardstep_required');
- }
-
- /**
- * Removes an item at the specified position.
- * @param integer the index of the item to be removed.
- * @return mixed the removed item.
- */
- public function removeAt($index)
- {
- $step=parent::removeAt($index);
- $this->_wizard->getMultiView()->getViews()->remove($step);
- $this->_wizard->removedWizardStep($step);
- return $step;
- }
-}
-
-
-/**
- * TWizardNavigationContainer class.
- *
- * TWizardNavigationContainer represents a control containing
- * a wizard navigation. The navigation may contain a few buttons, including
- * {@link getPreviousButton PreviousButton}, {@link getNextButton NextButton},
- * {@link getCancelButton CancelButton}, {@link getCompleteButton CompleteButton}.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationContainer extends TControl implements INamingContainer
-{
- private $_previousButton=null;
- private $_nextButton=null;
- private $_cancelButton=null;
- private $_completeButton=null;
-
- /**
- * @return mixed the previous button
- */
- public function getPreviousButton()
- {
- return $this->_previousButton;
- }
-
- /**
- * @param mixed the previous button
- */
- public function setPreviousButton($value)
- {
- $this->_previousButton=$value;
- }
-
- /**
- * @return mixed the next button
- */
- public function getNextButton()
- {
- return $this->_nextButton;
- }
-
- /**
- * @param mixed the next button
- */
- public function setNextButton($value)
- {
- $this->_nextButton=$value;
- }
-
- /**
- * @return mixed the cancel button
- */
- public function getCancelButton()
- {
- return $this->_cancelButton;
- }
-
- /**
- * @param mixed the cancel button
- */
- public function setCancelButton($value)
- {
- $this->_cancelButton=$value;
- }
-
- /**
- * @return mixed the complete button
- */
- public function getCompleteButton()
- {
- return $this->_completeButton;
- }
-
- /**
- * @param mixed the complete button
- */
- public function setCompleteButton($value)
- {
- $this->_completeButton=$value;
- }
-}
-
-
-/**
- * TWizardNavigationEventParameter class.
- *
- * TWizardNavigationEventParameter represents the parameter for
- * {@link TWizard}'s navigation events.
- *
- * The index of the currently active step can be obtained from
- * {@link getCurrentStepIndex CurrentStepIndex}, while the index
- * of the candidate new step is in {@link getNextStepIndex NextStepIndex}.
- * By modifying {@link setNextStepIndex NextStepIndex}, the new step
- * can be changed to another one. If there is anything wrong with
- * the navigation and it is not wanted, set {@link setCancelNavigation CancelNavigation}
- * to true.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationEventParameter extends TEventParameter
-{
- private $_cancel=false;
- private $_currentStep;
- private $_nextStep;
-
- /**
- * Constructor.
- * @param integer current step index
- */
- public function __construct($currentStep)
- {
- $this->_currentStep=$currentStep;
- $this->_nextStep=$currentStep;
- }
-
- /**
- * @return integer the zero-based index of the currently active step.
- */
- public function getCurrentStepIndex()
- {
- return $this->_currentStep;
- }
-
- /**
- * @return integer the zero-based index of the next step. Default to {@link getCurrentStepIndex CurrentStepIndex}.
- */
- public function getNextStepIndex()
- {
- return $this->_nextStep;
- }
-
- /**
- * @param integer the zero-based index of the next step.
- */
- public function setNextStepIndex($index)
- {
- $this->_nextStep=TPropertyValue::ensureInteger($index);
- }
-
- /**
- * @return boolean whether navigation to the next step should be canceled. Default to false.
- */
- public function getCancelNavigation()
- {
- return $this->_cancel;
- }
-
- /**
- * @param boolean whether navigation to the next step should be canceled.
- */
- public function setCancelNavigation($value)
- {
- $this->_cancel=TPropertyValue::ensureBoolean($value);
- }
-}
-
-/**
- * TWizardSideBarTemplate class.
- * TWizardSideBarTemplate is the default template for wizard sidebar.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardSideBarTemplate extends TComponent implements ITemplate
-{
- /**
- * Instantiates the template.
- * It creates a {@link TDataList} control.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $dataList=new TDataList;
- $dataList->setID(TWizard::ID_SIDEBAR_LIST);
- $dataList->getSelectedItemStyle()->getFont()->setBold(true);
- $dataList->setItemTemplate(new TWizardSideBarListItemTemplate);
- $parent->getControls()->add($dataList);
- }
-}
-
-/**
- * TWizardSideBarListItemTemplate class.
- * TWizardSideBarListItemTemplate is the default template for each item in the sidebar datalist.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardSideBarListItemTemplate extends TComponent implements ITemplate
-{
- /**
- * Instantiates the template.
- * It creates a {@link TLinkButton}.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $button=new TLinkButton;
- $button->setID(TWizard::ID_SIDEBAR_BUTTON);
- $parent->getControls()->add($button);
- }
-}
-
-/**
- * TWizardNavigationTemplate class.
- * TWizardNavigationTemplate is the base class for various navigation templates.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationTemplate extends TComponent implements ITemplate
-{
- private $_wizard;
-
- /**
- * Constructor.
- * @param TWizard the wizard owning this template
- */
- public function __construct($wizard)
- {
- $this->_wizard=$wizard;
- }
-
- /**
- * @return TWizard the wizard owning this template
- */
- public function getWizard()
- {
- return $this->_wizard;
- }
-
- /**
- * Instantiates the template.
- * Derived classes should override this method.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- }
-
- /**
- * Creates a navigation button.
- * It creates a {@link TButton}, {@link TLinkButton}, or {@link TImageButton},
- * depending on the given parameters.
- * @param TWizardNavigationButtonStyle button style
- * @param boolean whether the button should cause validation
- * @param string command name for the button's OnCommand event
- * @throws TInvalidDataValueException if the button type is not recognized
- */
- protected function createNavigationButton($buttonStyle,$causesValidation,$commandName)
- {
- switch($buttonStyle->getButtonType())
- {
- case TWizardNavigationButtonType::Button:
- $button=new TButton;
- break;
- case TWizardNavigationButtonType::Link:
- $button=new TLinkButton;
- break;
- case TWizardNavigationButtonType::Image:
- $button=new TImageButton;
- $button->setImageUrl($buttonStyle->getImageUrl());
- break;
- default:
- throw new TInvalidDataValueException('wizard_buttontype_unknown',$buttonStyle->getButtonType());
- }
- $button->setText($buttonStyle->getButtonText());
- $button->setCausesValidation($causesValidation);
- $button->setCommandName($commandName);
- return $button;
- }
-}
-
-/**
- * TWizardStartNavigationTemplate class.
- * TWizardStartNavigationTemplate is the template used as default wizard start navigation panel.
- * It consists of two buttons, Next and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStartNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $nextButton=$this->createNavigationButton($this->getWizard()->getStartNextButtonStyle(),true,TWizard::CMD_NEXT);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($nextButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setNextButton($nextButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-/**
- * TWizardFinishNavigationTemplate class.
- * TWizardFinishNavigationTemplate is the template used as default wizard finish navigation panel.
- * It consists of three buttons, Previous, Complete and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardFinishNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $previousButton=$this->createNavigationButton($this->getWizard()->getFinishPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
- $completeButton=$this->createNavigationButton($this->getWizard()->getFinishCompleteButtonStyle(),true,TWizard::CMD_COMPLETE);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($previousButton);
- $controls->add("\n");
- $controls->add($completeButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setPreviousButton($previousButton);
- $parent->setCompleteButton($completeButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-/**
- * TWizardStepNavigationTemplate class.
- * TWizardStepNavigationTemplate is the template used as default wizard step navigation panel.
- * It consists of three buttons, Previous, Next and Cancel.
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardStepNavigationTemplate extends TWizardNavigationTemplate
-{
- /**
- * Instantiates the template.
- * @param TControl parent to hold the content within the template
- */
- public function instantiateIn($parent)
- {
- $previousButton=$this->createNavigationButton($this->getWizard()->getStepPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
- $nextButton=$this->createNavigationButton($this->getWizard()->getStepNextButtonStyle(),true,TWizard::CMD_NEXT);
- $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
-
- $controls=$parent->getControls();
- $controls->add($previousButton);
- $controls->add("\n");
- $controls->add($nextButton);
- $controls->add("\n");
- $controls->add($cancelButton);
-
- $parent->setPreviousButton($previousButton);
- $parent->setNextButton($nextButton);
- $parent->setCancelButton($cancelButton);
- }
-}
-
-
-/**
- * TWizardNavigationButtonType class.
- * TWizardNavigationButtonType defines the enumerable type for the possible types of buttons
- * that can be used in the navigation part of a {@link TWizard}.
- *
- * The following enumerable values are defined:
- * - Button: a regular click button
- * - Image: an image button
- * - Link: a hyperlink button
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TWizardNavigationButtonType extends TEnumerable
-{
- const Button='Button';
- const Image='Image';
- const Link='Link';
-}
-
-
-/**
- * TWizardStepType class.
- * TWizardStepType defines the enumerable type for the possible types of {@link TWizard wizard} steps.
- *
- * The following enumerable values are defined:
- * - Auto: the type is automatically determined based on the location of the wizard step in the whole step collection.
- * - Complete: the step is the last summary step.
- * - Start: the step is the first step
- * - Step: the step is between the begin and the end steps.
- * - Finish: the last step before the Complete step.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0.4
- */
-class TWizardStepType extends TEnumerable
-{
- const Auto='Auto';
- const Complete='Complete';
- const Start='Start';
- const Step='Step';
- const Finish='Finish';
-}
-
+ $requestedIndex=TPropertyValue::ensureInteger($requestedStep);
+ $navParam->setNextStepIndex($requestedIndex);
+ $handled=true;
+ }
+
+ if($handled)
+ {
+ if(!$navParam->getCancelNavigation())
+ {
+ $nextStepIndex=$navParam->getNextStepIndex();
+ if(!$this->_activeStepIndexSet && $this->allowNavigationToStep($nextStepIndex))
+ {
+ if($movePrev)
+ $this->getPreviousStepIndex(true); // pop out the previous move from history
+ $this->setActiveStepIndex($nextStepIndex);
+ }
+ }
+ else
+ $this->setActiveStepIndex($index);
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+
+/**
+ * TWizardStep class.
+ *
+ * TWizardStep represents a wizard step. The wizard owning the step
+ * can be obtained by {@link getWizard Wizard}.
+ * To specify the type of the step, set {@link setStepType StepType};
+ * For step title, set {@link setTitle Title}. If a step can be re-visited,
+ * set {@link setAllowReturn AllowReturn} to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStep extends TView
+{
+ private $_wizard;
+
+ /**
+ * @return TWizard the wizard owning this step
+ */
+ public function getWizard()
+ {
+ return $this->_wizard;
+ }
+
+ /**
+ * Sets the wizard owning this step.
+ * This method is used internally by {@link TWizard}.
+ * @param TWizard the wizard owning this step
+ */
+ public function setWizard($wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * @return string the title for this step.
+ */
+ public function getTitle()
+ {
+ return $this->getViewState('Title','');
+ }
+
+ /**
+ * @param string the title for this step.
+ */
+ public function setTitle($value)
+ {
+ $this->setViewState('Title',$value,'');
+ if($this->_wizard)
+ $this->_wizard->wizardStepsChanged();
+ }
+
+ /**
+ * @return boolean whether this step can be re-visited. Default to true.
+ */
+ public function getAllowReturn()
+ {
+ return $this->getViewState('AllowReturn',true);
+ }
+
+ /**
+ * @param boolean whether this step can be re-visited.
+ */
+ public function setAllowReturn($value)
+ {
+ $this->setViewState('AllowReturn',TPropertyValue::ensureBoolean($value),true);
+ }
+
+ /**
+ * @return TWizardStepType the wizard step type. Defaults to TWizardStepType::Auto.
+ */
+ public function getStepType()
+ {
+ return $this->getViewState('StepType',TWizardStepType::Auto);
+ }
+
+ /**
+ * @param TWizardStepType the wizard step type.
+ */
+ public function setStepType($type)
+ {
+ $type=TPropertyValue::ensureEnum($type,'TWizardStepType');
+ if($type!==$this->getStepType())
+ {
+ $this->setViewState('StepType',$type,TWizardStepType::Auto);
+ if($this->_wizard)
+ $this->_wizard->wizardStepsChanged();
+ }
+ }
+}
+
+
+/**
+ * TCompleteWizardStep class.
+ *
+ * TCompleteWizardStep represents a wizard step of type TWizardStepType::Complete.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TCompleteWizardStep extends TWizardStep
+{
+ /**
+ * @return TWizardStepType the wizard step type. Always TWizardStepType::Complete.
+ */
+ public function getStepType()
+ {
+ return TWizardStepType::Complete;
+ }
+
+ /**
+ * @param string the wizard step type.
+ * @throws TInvalidOperationException whenever this method is invoked.
+ */
+ public function setStepType($value)
+ {
+ throw new TInvalidOperationException('completewizardstep_steptype_readonly');
+ }
+}
+
+
+/**
+ * TTemplatedWizardStep class.
+ *
+ * TTemplatedWizardStep represents a wizard step whose content and navigation
+ * can be customized using templates. To customize the step content, specify
+ * {@link setContentTemplate ContentTemplate}. To customize navigation specific
+ * to the step, specify {@link setNavigationTemplate NavigationTemplate}. Note,
+ * if the navigation template is not specified, default navigation will be used.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TTemplatedWizardStep extends TWizardStep implements INamingContainer
+{
+ /**
+ * @var ITemplate the template for displaying the navigation UI of a wizard step.
+ */
+ private $_navigationTemplate=null;
+ /**
+ * @var ITemplate the template for displaying the content within the wizard step.
+ */
+ private $_contentTemplate=null;
+ /**
+ * @var TWizardNavigationContainer
+ */
+ private $_navigationContainer=null;
+
+ /**
+ * Creates child controls.
+ * This method mainly instantiates the content template, if any.
+ */
+ public function createChildControls()
+ {
+ $this->getControls()->clear();
+ if($this->_contentTemplate)
+ $this->_contentTemplate->instantiateIn($this);
+ }
+
+ /**
+ * Ensures child controls are created.
+ * @param mixed event parameter
+ */
+ public function onInit($param)
+ {
+ parent::onInit($param);
+ $this->ensureChildControls();
+ }
+
+ /**
+ * @return ITemplate the template for the content of the wizard step.
+ */
+ public function getContentTemplate()
+ {
+ return $this->_contentTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for the content of the wizard step.
+ */
+ public function setContentTemplate($value)
+ {
+ $this->_contentTemplate=$value;
+ }
+
+ /**
+ * @return ITemplate the template for displaying the navigation UI of a wizard step. Defaults to null.
+ */
+ public function getNavigationTemplate()
+ {
+ return $this->_navigationTemplate;
+ }
+
+ /**
+ * @param ITemplate the template for displaying the navigation UI of a wizard step.
+ */
+ public function setNavigationTemplate($value)
+ {
+ $this->_navigationTemplate=$value;
+ }
+
+ /**
+ * @return TWizardNavigationContainer the control containing the navigation.
+ * It could be null if no navigation template is specified.
+ */
+ public function getNavigationContainer()
+ {
+ return $this->_navigationContainer;
+ }
+
+ /**
+ * Instantiates the navigation template if any
+ */
+ public function instantiateNavigationTemplate()
+ {
+ if(!$this->_navigationContainer && $this->_navigationTemplate)
+ {
+ $this->_navigationContainer=new TWizardNavigationContainer;
+ $this->_navigationTemplate->instantiateIn($this->_navigationContainer);
+ }
+ }
+}
+
+
+/**
+ * TWizardStepCollection class.
+ *
+ * TWizardStepCollection represents the collection of wizard steps owned
+ * by a {@link TWizard}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStepCollection extends TList
+{
+ /**
+ * @var TWizard
+ */
+ private $_wizard;
+
+ /**
+ * Constructor.
+ * @param TWizard wizard that owns this collection
+ */
+ public function __construct(TWizard $wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * Inserts an item at the specified position.
+ * This method overrides the parent implementation by checking if
+ * the item being added is a {@link TWizardStep}.
+ * @param integer the speicified position.
+ * @param mixed new item
+ * @throws TInvalidDataTypeException if the item being added is not TWizardStep.
+ */
+ public function insertAt($index,$item)
+ {
+ if($item instanceof TWizardStep)
+ {
+ parent::insertAt($index,$item);
+ $this->_wizard->getMultiView()->getViews()->insertAt($index,$item);
+ $this->_wizard->addedWizardStep($item);
+ }
+ else
+ throw new TInvalidDataTypeException('wizardstepcollection_wizardstep_required');
+ }
+
+ /**
+ * Removes an item at the specified position.
+ * @param integer the index of the item to be removed.
+ * @return mixed the removed item.
+ */
+ public function removeAt($index)
+ {
+ $step=parent::removeAt($index);
+ $this->_wizard->getMultiView()->getViews()->remove($step);
+ $this->_wizard->removedWizardStep($step);
+ return $step;
+ }
+}
+
+
+/**
+ * TWizardNavigationContainer class.
+ *
+ * TWizardNavigationContainer represents a control containing
+ * a wizard navigation. The navigation may contain a few buttons, including
+ * {@link getPreviousButton PreviousButton}, {@link getNextButton NextButton},
+ * {@link getCancelButton CancelButton}, {@link getCompleteButton CompleteButton}.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationContainer extends TControl implements INamingContainer
+{
+ private $_previousButton=null;
+ private $_nextButton=null;
+ private $_cancelButton=null;
+ private $_completeButton=null;
+
+ /**
+ * @return mixed the previous button
+ */
+ public function getPreviousButton()
+ {
+ return $this->_previousButton;
+ }
+
+ /**
+ * @param mixed the previous button
+ */
+ public function setPreviousButton($value)
+ {
+ $this->_previousButton=$value;
+ }
+
+ /**
+ * @return mixed the next button
+ */
+ public function getNextButton()
+ {
+ return $this->_nextButton;
+ }
+
+ /**
+ * @param mixed the next button
+ */
+ public function setNextButton($value)
+ {
+ $this->_nextButton=$value;
+ }
+
+ /**
+ * @return mixed the cancel button
+ */
+ public function getCancelButton()
+ {
+ return $this->_cancelButton;
+ }
+
+ /**
+ * @param mixed the cancel button
+ */
+ public function setCancelButton($value)
+ {
+ $this->_cancelButton=$value;
+ }
+
+ /**
+ * @return mixed the complete button
+ */
+ public function getCompleteButton()
+ {
+ return $this->_completeButton;
+ }
+
+ /**
+ * @param mixed the complete button
+ */
+ public function setCompleteButton($value)
+ {
+ $this->_completeButton=$value;
+ }
+}
+
+
+/**
+ * TWizardNavigationEventParameter class.
+ *
+ * TWizardNavigationEventParameter represents the parameter for
+ * {@link TWizard}'s navigation events.
+ *
+ * The index of the currently active step can be obtained from
+ * {@link getCurrentStepIndex CurrentStepIndex}, while the index
+ * of the candidate new step is in {@link getNextStepIndex NextStepIndex}.
+ * By modifying {@link setNextStepIndex NextStepIndex}, the new step
+ * can be changed to another one. If there is anything wrong with
+ * the navigation and it is not wanted, set {@link setCancelNavigation CancelNavigation}
+ * to true.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationEventParameter extends TEventParameter
+{
+ private $_cancel=false;
+ private $_currentStep;
+ private $_nextStep;
+
+ /**
+ * Constructor.
+ * @param integer current step index
+ */
+ public function __construct($currentStep)
+ {
+ $this->_currentStep=$currentStep;
+ $this->_nextStep=$currentStep;
+ }
+
+ /**
+ * @return integer the zero-based index of the currently active step.
+ */
+ public function getCurrentStepIndex()
+ {
+ return $this->_currentStep;
+ }
+
+ /**
+ * @return integer the zero-based index of the next step. Default to {@link getCurrentStepIndex CurrentStepIndex}.
+ */
+ public function getNextStepIndex()
+ {
+ return $this->_nextStep;
+ }
+
+ /**
+ * @param integer the zero-based index of the next step.
+ */
+ public function setNextStepIndex($index)
+ {
+ $this->_nextStep=TPropertyValue::ensureInteger($index);
+ }
+
+ /**
+ * @return boolean whether navigation to the next step should be canceled. Default to false.
+ */
+ public function getCancelNavigation()
+ {
+ return $this->_cancel;
+ }
+
+ /**
+ * @param boolean whether navigation to the next step should be canceled.
+ */
+ public function setCancelNavigation($value)
+ {
+ $this->_cancel=TPropertyValue::ensureBoolean($value);
+ }
+}
+
+/**
+ * TWizardSideBarTemplate class.
+ * TWizardSideBarTemplate is the default template for wizard sidebar.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardSideBarTemplate extends TComponent implements ITemplate
+{
+ /**
+ * Instantiates the template.
+ * It creates a {@link TDataList} control.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $dataList=new TDataList;
+ $dataList->setID(TWizard::ID_SIDEBAR_LIST);
+ $dataList->getSelectedItemStyle()->getFont()->setBold(true);
+ $dataList->setItemTemplate(new TWizardSideBarListItemTemplate);
+ $parent->getControls()->add($dataList);
+ }
+}
+
+/**
+ * TWizardSideBarListItemTemplate class.
+ * TWizardSideBarListItemTemplate is the default template for each item in the sidebar datalist.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardSideBarListItemTemplate extends TComponent implements ITemplate
+{
+ /**
+ * Instantiates the template.
+ * It creates a {@link TLinkButton}.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $button=new TLinkButton;
+ $button->setID(TWizard::ID_SIDEBAR_BUTTON);
+ $parent->getControls()->add($button);
+ }
+}
+
+/**
+ * TWizardNavigationTemplate class.
+ * TWizardNavigationTemplate is the base class for various navigation templates.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationTemplate extends TComponent implements ITemplate
+{
+ private $_wizard;
+
+ /**
+ * Constructor.
+ * @param TWizard the wizard owning this template
+ */
+ public function __construct($wizard)
+ {
+ $this->_wizard=$wizard;
+ }
+
+ /**
+ * @return TWizard the wizard owning this template
+ */
+ public function getWizard()
+ {
+ return $this->_wizard;
+ }
+
+ /**
+ * Instantiates the template.
+ * Derived classes should override this method.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ }
+
+ /**
+ * Creates a navigation button.
+ * It creates a {@link TButton}, {@link TLinkButton}, or {@link TImageButton},
+ * depending on the given parameters.
+ * @param TWizardNavigationButtonStyle button style
+ * @param boolean whether the button should cause validation
+ * @param string command name for the button's OnCommand event
+ * @throws TInvalidDataValueException if the button type is not recognized
+ */
+ protected function createNavigationButton($buttonStyle,$causesValidation,$commandName)
+ {
+ switch($buttonStyle->getButtonType())
+ {
+ case TWizardNavigationButtonType::Button:
+ $button=new TButton;
+ break;
+ case TWizardNavigationButtonType::Link:
+ $button=new TLinkButton;
+ break;
+ case TWizardNavigationButtonType::Image:
+ $button=new TImageButton;
+ $button->setImageUrl($buttonStyle->getImageUrl());
+ break;
+ default:
+ throw new TInvalidDataValueException('wizard_buttontype_unknown',$buttonStyle->getButtonType());
+ }
+ $button->setText($buttonStyle->getButtonText());
+ $button->setCausesValidation($causesValidation);
+ $button->setCommandName($commandName);
+ return $button;
+ }
+}
+
+/**
+ * TWizardStartNavigationTemplate class.
+ * TWizardStartNavigationTemplate is the template used as default wizard start navigation panel.
+ * It consists of two buttons, Next and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStartNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $nextButton=$this->createNavigationButton($this->getWizard()->getStartNextButtonStyle(),true,TWizard::CMD_NEXT);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($nextButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setNextButton($nextButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+/**
+ * TWizardFinishNavigationTemplate class.
+ * TWizardFinishNavigationTemplate is the template used as default wizard finish navigation panel.
+ * It consists of three buttons, Previous, Complete and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardFinishNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $previousButton=$this->createNavigationButton($this->getWizard()->getFinishPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
+ $completeButton=$this->createNavigationButton($this->getWizard()->getFinishCompleteButtonStyle(),true,TWizard::CMD_COMPLETE);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($previousButton);
+ $controls->add("\n");
+ $controls->add($completeButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setPreviousButton($previousButton);
+ $parent->setCompleteButton($completeButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+/**
+ * TWizardStepNavigationTemplate class.
+ * TWizardStepNavigationTemplate is the template used as default wizard step navigation panel.
+ * It consists of three buttons, Previous, Next and Cancel.
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardStepNavigationTemplate extends TWizardNavigationTemplate
+{
+ /**
+ * Instantiates the template.
+ * @param TControl parent to hold the content within the template
+ */
+ public function instantiateIn($parent)
+ {
+ $previousButton=$this->createNavigationButton($this->getWizard()->getStepPreviousButtonStyle(),false,TWizard::CMD_PREVIOUS);
+ $nextButton=$this->createNavigationButton($this->getWizard()->getStepNextButtonStyle(),true,TWizard::CMD_NEXT);
+ $cancelButton=$this->createNavigationButton($this->getWizard()->getCancelButtonStyle(),false,TWizard::CMD_CANCEL);
+
+ $controls=$parent->getControls();
+ $controls->add($previousButton);
+ $controls->add("\n");
+ $controls->add($nextButton);
+ $controls->add("\n");
+ $controls->add($cancelButton);
+
+ $parent->setPreviousButton($previousButton);
+ $parent->setNextButton($nextButton);
+ $parent->setCancelButton($cancelButton);
+ }
+}
+
+
+/**
+ * TWizardNavigationButtonType class.
+ * TWizardNavigationButtonType defines the enumerable type for the possible types of buttons
+ * that can be used in the navigation part of a {@link TWizard}.
+ *
+ * The following enumerable values are defined:
+ * - Button: a regular click button
+ * - Image: an image button
+ * - Link: a hyperlink button
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TWizardNavigationButtonType extends TEnumerable
+{
+ const Button='Button';
+ const Image='Image';
+ const Link='Link';
+}
+
+
+/**
+ * TWizardStepType class.
+ * TWizardStepType defines the enumerable type for the possible types of {@link TWizard wizard} steps.
+ *
+ * The following enumerable values are defined:
+ * - Auto: the type is automatically determined based on the location of the wizard step in the whole step collection.
+ * - Complete: the step is the last summary step.
+ * - Start: the step is the first step
+ * - Step: the step is between the begin and the end steps.
+ * - Finish: the last step before the Complete step.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0.4
+ */
+class TWizardStepType extends TEnumerable
+{
+ const Auto='Auto';
+ const Complete='Complete';
+ const Start='Start';
+ const Step='Step';
+ const Finish='Finish';
+}
+
diff --git a/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php b/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php
index 0e05c556..c3b4b603 100644
--- a/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php
+++ b/framework/Web/UI/WebControls/TWizardNavigationButtonStyle.php
@@ -1,155 +1,155 @@
-<?php
-/**
- * TWizardNavigationButtonStyle class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
+<?php
+/**
+ * TWizardNavigationButtonStyle class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
* @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id $
- * @package System.Web.UI.WebControls
- */
-
-/**
- * Includes TStyle class file
- */
-Prado::using('System.Web.UI.WebControls.TStyle');
-
-/**
- * TWizardNavigationButtonStyle class.
- * TWizardNavigationButtonStyle defines the style applied to a wizard navigation button.
- * The button type can be specified via {@link setButtonType ButtonType}, which
- * can be 'Button', 'Image' or 'Link'.
- * If the button is an image button, {@link setImageUrl ImageUrl} will be
- * used to load the image for the button.
- * Otherwise, {@link setButtonText ButtonText} will be displayed as the button caption.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @version $Id$
- * @package System.Web.UI.WebControls
- * @since 3.0
- */
-class TWizardNavigationButtonStyle extends TStyle
-{
- private $_imageUrl=null;
- private $_buttonText=null;
- private $_buttonType=null;
-
- /**
- * Sets the style attributes to default values.
- * This method overrides the parent implementation by
- * resetting additional TWizardNavigationButtonStyle specific attributes.
- */
- public function reset()
- {
- parent::reset();
- $this->_imageUrl=null;
- $this->_buttonText=null;
- $this->_buttonType=null;
- }
-
- /**
- * Copies the fields in a new style to this style.
- * If a style field is set in the new style, the corresponding field
- * in this style will be overwritten.
- * @param TStyle the new style
- */
- public function copyFrom($style)
- {
- parent::copyFrom($style);
- if($style instanceof TWizardNavigationButtonStyle)
- {
- if($this->_imageUrl===null && $style->_imageUrl!==null)
- $this->_imageUrl=$style->_imageUrl;
- if($this->_buttonText===null && $style->_buttonText!==null)
- $this->_buttonText=$style->_buttonText;
- if($this->_buttonType===null && $style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * Merges the style with a new one.
- * If a style field is not set in this style, it will be overwritten by
- * the new one.
- * @param TStyle the new style
- */
- public function mergeWith($style)
- {
- parent::mergeWith($style);
- if($style instanceof TWizardNavigationButtonStyle)
- {
- if($style->_imageUrl!==null)
- $this->_imageUrl=$style->_imageUrl;
- if($style->_buttonText!==null)
- $this->_buttonText=$style->_buttonText;
- if($style->_buttonType!==null)
- $this->_buttonType=$style->_buttonType;
- }
- }
-
- /**
- * @return string image URL for the image button
- */
- public function getImageUrl()
- {
- return $this->_imageUrl===null?'':$this->_imageUrl;
- }
-
- /**
- * @param string image URL for the image button
- */
- public function setImageUrl($value)
- {
- $this->_imageUrl=$value;
- }
-
- /**
- * @return string button caption
- */
- public function getButtonText()
- {
- return $this->_buttonText===null?'':$this->_buttonText;
- }
-
- /**
- * @param string button caption
- */
- public function setButtonText($value)
- {
- $this->_buttonText=$value;
- }
-
- /**
- * @return TWizardNavigationButtonType button type. Default to TWizardNavigationButtonType::Button.
- */
- public function getButtonType()
- {
- return $this->_buttonType===null? TWizardNavigationButtonType::Button :$this->_buttonType;
- }
-
- /**
- * @param TWizardNavigationButtonType button type.
- */
- public function setButtonType($value)
- {
- $this->_buttonType=TPropertyValue::ensureEnum($value,'TWizardNavigationButtonType');
- }
-
- /**
- * Applies this style to the specified button
- * @param mixed button to be applied with this style
- */
- public function apply($button)
- {
- if($button instanceof TImageButton)
- {
- if($button->getImageUrl()==='')
- $button->setImageUrl($this->getImageUrl());
- }
- if($button->getText()==='')
- $button->setText($this->getButtonText());
- $button->getStyle()->mergeWith($this);
- }
-}
-
+ * @license http://www.pradosoft.com/license/
+ * @version $Id $
+ * @package System.Web.UI.WebControls
+ */
+
+/**
+ * Includes TStyle class file
+ */
+Prado::using('System.Web.UI.WebControls.TStyle');
+
+/**
+ * TWizardNavigationButtonStyle class.
+ * TWizardNavigationButtonStyle defines the style applied to a wizard navigation button.
+ * The button type can be specified via {@link setButtonType ButtonType}, which
+ * can be 'Button', 'Image' or 'Link'.
+ * If the button is an image button, {@link setImageUrl ImageUrl} will be
+ * used to load the image for the button.
+ * Otherwise, {@link setButtonText ButtonText} will be displayed as the button caption.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id$
+ * @package System.Web.UI.WebControls
+ * @since 3.0
+ */
+class TWizardNavigationButtonStyle extends TStyle
+{
+ private $_imageUrl=null;
+ private $_buttonText=null;
+ private $_buttonType=null;
+
+ /**
+ * Sets the style attributes to default values.
+ * This method overrides the parent implementation by
+ * resetting additional TWizardNavigationButtonStyle specific attributes.
+ */
+ public function reset()
+ {
+ parent::reset();
+ $this->_imageUrl=null;
+ $this->_buttonText=null;
+ $this->_buttonType=null;
+ }
+
+ /**
+ * Copies the fields in a new style to this style.
+ * If a style field is set in the new style, the corresponding field
+ * in this style will be overwritten.
+ * @param TStyle the new style
+ */
+ public function copyFrom($style)
+ {
+ parent::copyFrom($style);
+ if($style instanceof TWizardNavigationButtonStyle)
+ {
+ if($this->_imageUrl===null && $style->_imageUrl!==null)
+ $this->_imageUrl=$style->_imageUrl;
+ if($this->_buttonText===null && $style->_buttonText!==null)
+ $this->_buttonText=$style->_buttonText;
+ if($this->_buttonType===null && $style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * Merges the style with a new one.
+ * If a style field is not set in this style, it will be overwritten by
+ * the new one.
+ * @param TStyle the new style
+ */
+ public function mergeWith($style)
+ {
+ parent::mergeWith($style);
+ if($style instanceof TWizardNavigationButtonStyle)
+ {
+ if($style->_imageUrl!==null)
+ $this->_imageUrl=$style->_imageUrl;
+ if($style->_buttonText!==null)
+ $this->_buttonText=$style->_buttonText;
+ if($style->_buttonType!==null)
+ $this->_buttonType=$style->_buttonType;
+ }
+ }
+
+ /**
+ * @return string image URL for the image button
+ */
+ public function getImageUrl()
+ {
+ return $this->_imageUrl===null?'':$this->_imageUrl;
+ }
+
+ /**
+ * @param string image URL for the image button
+ */
+ public function setImageUrl($value)
+ {
+ $this->_imageUrl=$value;
+ }
+
+ /**
+ * @return string button caption
+ */
+ public function getButtonText()
+ {
+ return $this->_buttonText===null?'':$this->_buttonText;
+ }
+
+ /**
+ * @param string button caption
+ */
+ public function setButtonText($value)
+ {
+ $this->_buttonText=$value;
+ }
+
+ /**
+ * @return TWizardNavigationButtonType button type. Default to TWizardNavigationButtonType::Button.
+ */
+ public function getButtonType()
+ {
+ return $this->_buttonType===null? TWizardNavigationButtonType::Button :$this->_buttonType;
+ }
+
+ /**
+ * @param TWizardNavigationButtonType button type.
+ */
+ public function setButtonType($value)
+ {
+ $this->_buttonType=TPropertyValue::ensureEnum($value,'TWizardNavigationButtonType');
+ }
+
+ /**
+ * Applies this style to the specified button
+ * @param mixed button to be applied with this style
+ */
+ public function apply($button)
+ {
+ if($button instanceof TImageButton)
+ {
+ if($button->getImageUrl()==='')
+ $button->setImageUrl($this->getImageUrl());
+ }
+ if($button->getText()==='')
+ $button->setText($this->getButtonText());
+ $button->getStyle()->mergeWith($this);
+ }
+}
+
diff --git a/framework/Web/UI/WebControls/assets/captcha.php b/framework/Web/UI/WebControls/assets/captcha.php
index b26df895..08a857b5 100644
--- a/framework/Web/UI/WebControls/assets/captcha.php
+++ b/framework/Web/UI/WebControls/assets/captcha.php
@@ -1,224 +1,224 @@
-<?php
-/**
- * CAPTCHA generator script.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.pradosoft.com/
- * @copyright Copyright &copy; 2005-2012 PradoSoft
- * @license http://www.pradosoft.com/license/
- * @version $Id$
- * @package System.Web.UI.WebControls.assets
- */
-
-define('THEME_OPAQUE_BACKGROUND',0x0001);
-define('THEME_NOISY_BACKGROUND',0x0002);
-define('THEME_HAS_GRID',0x0004);
-define('THEME_HAS_SCRIBBLE',0x0008);
-define('THEME_MORPH_BACKGROUND',0x0010);
-define('THEME_SHADOWED_TEXT',0x0020);
-
-require_once(dirname(__FILE__).'/captcha_key.php');
-
-$token='error';
-$theme=0;
-
-if(isset($_GET['options']))
-{
- $str=base64_decode($_GET['options']);
- if(strlen($str)>32)
- {
- $hash=substr($str,0,32);
- $str=substr($str,32);
- if(md5($privateKey.$str)===$hash)
- {
- $options=unserialize($str);
- $publicKey=$options['publicKey'];
- $tokenLength=$options['tokenLength'];
- $caseSensitive=$options['caseSensitive'];
- $alphabet=$options['alphabet'];
- $fontSize=$options['fontSize'];
- $theme=$options['theme'];
- if(($randomSeed=$options['randomSeed'])>0)
- srand($randomSeed);
- else
- srand((int)(microtime()*1000000));
- $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive);
- }
- }
-}
-
-displayToken($token,$fontSize,$theme);
-
-function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
-{
- $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
- return $caseSensitive?$token:strtoupper($token);
-}
-
-function hash2string($hex,$alphabet)
-{
- if(strlen($alphabet)<2)
- $alphabet='234578adefhijmnrtABDEFGHJLMNRT';
- $hexLength=strlen($hex);
- $base=strlen($alphabet);
- $result='';
- for($i=0;$i<$hexLength;$i+=6)
- {
- $number=hexdec(substr($hex,$i,6));
- while($number)
- {
- $result.=$alphabet[$number%$base];
- $number=floor($number/$base);
- }
- }
- return $result;
-}
-
-function displayToken($token,$fontSize,$theme)
-{
- if(($fontSize=(int)$fontSize)<22)
- $fontSize=22;
- if($fontSize>100)
- $fontSize=100;
- $length=strlen($token);
- $padding=10;
- $fontWidth=$fontSize;
- $fontHeight=floor($fontWidth*1.5);
- $width=$fontWidth*$length+$padding*2;
- $height=$fontHeight;
- $image=imagecreatetruecolor($width,$height);
-
- addBackground
- (
- $image, $width, $height,
- $theme&THEME_OPAQUE_BACKGROUND,
- $theme&THEME_NOISY_BACKGROUND,
- $theme&THEME_HAS_GRID,
- $theme&THEME_HAS_SCRIBBLE,
- $theme&THEME_MORPH_BACKGROUND
- );
-
- $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf';
-
- if(function_exists('imagefilter'))
- imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR);
-
- $hasShadow=($theme&THEME_SHADOWED_TEXT);
- for($i=0;$i<$length;$i++)
- {
- $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
- $size=rand($fontWidth-10,$fontWidth);
- $angle=rand(-30,30);
- $x=$padding+$i*$fontWidth;
- $y=rand($fontHeight-15,$fontHeight-10);
- imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]);
- if($hasShadow)
- imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]);
- imagecolordeallocate($image,$color);
- }
-
- header('Content-Type: image/png');
- imagepng($image);
- imagedestroy($image);
-}
-
-function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph)
-{
- $background=imagecreatetruecolor($width*2,$height*2);
- $white=imagecolorallocate($background,255,255,255);
- imagefill($background,0,0,$white);
-
- if($opaque)
- imagefill($background,0,0,imagecolorallocate($background,100,100,100));
-
- if($noisy)
- addNoise($background,$width*2,$height*2);
-
- if($hasGrid)
- addGrid($background,$width*2,$height*2);
-
- if($hasScribble)
- addScribble($background,$width*2,$height*2);
-
- if($morph)
- morphImage($background,$width*2,$height*2);
-
- imagecopy($image,$background,0,0,30,30,$width,$height);
-
- if(!$opaque)
- imagecolortransparent($image,$white);
-}
-
-function addNoise($image,$width,$height)
-{
- for($x=0;$x<$width;++$x)
- {
- for($y=0;$y<$height;++$y)
- {
- if(rand(0,100)<25)
- {
- $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
- imagesetpixel($image,$x,$y,$color);
- imagecolordeallocate($image,$color);
- }
- }
- }
-}
-
-function addGrid($image,$width,$height)
-{
- for($i=0;$i<$width;$i+=rand(15,25))
- {
- imagesetthickness($image,rand(2,6));
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color);
- imagecolordeallocate($image,$color);
- }
- for($i=0;$i<$height;$i+=rand(15,25))
- {
- imagesetthickness($image,rand(2,6));
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color);
- imagecolordeallocate($image,$color);
- }
-}
-
-function addScribble($image,$width,$height)
-{
- for($i=0;$i<8;$i++)
- {
- $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
- $points=array();
- for($j=1;$j<rand(5,10);$j++)
- {
- $points[]=rand(2*(20*($i+1)),2*(50*($i+1)));
- $points[]=rand(30,$height+30);
- }
- imagesetthickness($image,rand(2,6));
- imagepolygon($image,$points,intval(sizeof($points)/2),$color);
- imagecolordeallocate($image,$color);
- }
-}
-
-function morphImage($image,$width,$height)
-{
- $tempImage=imagecreatetruecolor($width,$height);
- $chunk=rand(1,5);
- for($x=$y=0;$x<$width;$x+=$chunk)
- {
- $chunk=rand(1,5);
- $y+=rand(-1,1);
- if($y>=$height) $y=$height-5;
- if($y<0) $y=5;
- imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height);
- }
- for($x=$y=0;$y<$height;$y+=$chunk)
- {
- $chunk=rand(1,5);
- $x+=rand(-1,1);
- if($x>=$width) $x=$width-5;
- if($x<0) $x=5;
- imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk);
- }
-}
-
+<?php
+/**
+ * CAPTCHA generator script.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2005-2012 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Id$
+ * @package System.Web.UI.WebControls.assets
+ */
+
+define('THEME_OPAQUE_BACKGROUND',0x0001);
+define('THEME_NOISY_BACKGROUND',0x0002);
+define('THEME_HAS_GRID',0x0004);
+define('THEME_HAS_SCRIBBLE',0x0008);
+define('THEME_MORPH_BACKGROUND',0x0010);
+define('THEME_SHADOWED_TEXT',0x0020);
+
+require_once(dirname(__FILE__).'/captcha_key.php');
+
+$token='error';
+$theme=0;
+
+if(isset($_GET['options']))
+{
+ $str=base64_decode($_GET['options']);
+ if(strlen($str)>32)
+ {
+ $hash=substr($str,0,32);
+ $str=substr($str,32);
+ if(md5($privateKey.$str)===$hash)
+ {
+ $options=unserialize($str);
+ $publicKey=$options['publicKey'];
+ $tokenLength=$options['tokenLength'];
+ $caseSensitive=$options['caseSensitive'];
+ $alphabet=$options['alphabet'];
+ $fontSize=$options['fontSize'];
+ $theme=$options['theme'];
+ if(($randomSeed=$options['randomSeed'])>0)
+ srand($randomSeed);
+ else
+ srand((int)(microtime()*1000000));
+ $token=generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive);
+ }
+ }
+}
+
+displayToken($token,$fontSize,$theme);
+
+function generateToken($publicKey,$privateKey,$alphabet,$tokenLength,$caseSensitive)
+{
+ $token=substr(hash2string(md5($publicKey.$privateKey),$alphabet).hash2string(md5($privateKey.$publicKey),$alphabet),0,$tokenLength);
+ return $caseSensitive?$token:strtoupper($token);
+}
+
+function hash2string($hex,$alphabet)
+{
+ if(strlen($alphabet)<2)
+ $alphabet='234578adefhijmnrtABDEFGHJLMNRT';
+ $hexLength=strlen($hex);
+ $base=strlen($alphabet);
+ $result='';
+ for($i=0;$i<$hexLength;$i+=6)
+ {
+ $number=hexdec(substr($hex,$i,6));
+ while($number)
+ {
+ $result.=$alphabet[$number%$base];
+ $number=floor($number/$base);
+ }
+ }
+ return $result;
+}
+
+function displayToken($token,$fontSize,$theme)
+{
+ if(($fontSize=(int)$fontSize)<22)
+ $fontSize=22;
+ if($fontSize>100)
+ $fontSize=100;
+ $length=strlen($token);
+ $padding=10;
+ $fontWidth=$fontSize;
+ $fontHeight=floor($fontWidth*1.5);
+ $width=$fontWidth*$length+$padding*2;
+ $height=$fontHeight;
+ $image=imagecreatetruecolor($width,$height);
+
+ addBackground
+ (
+ $image, $width, $height,
+ $theme&THEME_OPAQUE_BACKGROUND,
+ $theme&THEME_NOISY_BACKGROUND,
+ $theme&THEME_HAS_GRID,
+ $theme&THEME_HAS_SCRIBBLE,
+ $theme&THEME_MORPH_BACKGROUND
+ );
+
+ $font=dirname(__FILE__).DIRECTORY_SEPARATOR.'verase.ttf';
+
+ if(function_exists('imagefilter'))
+ imagefilter($image,IMG_FILTER_GAUSSIAN_BLUR);
+
+ $hasShadow=($theme&THEME_SHADOWED_TEXT);
+ for($i=0;$i<$length;$i++)
+ {
+ $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
+ $size=rand($fontWidth-10,$fontWidth);
+ $angle=rand(-30,30);
+ $x=$padding+$i*$fontWidth;
+ $y=rand($fontHeight-15,$fontHeight-10);
+ imagettftext($image,$size,$angle,$x,$y,$color,$font,$token[$i]);
+ if($hasShadow)
+ imagettftext($image,$size,$angle,$x+2,$y+2,$color,$font,$token[$i]);
+ imagecolordeallocate($image,$color);
+ }
+
+ header('Content-Type: image/png');
+ imagepng($image);
+ imagedestroy($image);
+}
+
+function addBackground($image,$width,$height,$opaque,$noisy,$hasGrid,$hasScribble,$morph)
+{
+ $background=imagecreatetruecolor($width*2,$height*2);
+ $white=imagecolorallocate($background,255,255,255);
+ imagefill($background,0,0,$white);
+
+ if($opaque)
+ imagefill($background,0,0,imagecolorallocate($background,100,100,100));
+
+ if($noisy)
+ addNoise($background,$width*2,$height*2);
+
+ if($hasGrid)
+ addGrid($background,$width*2,$height*2);
+
+ if($hasScribble)
+ addScribble($background,$width*2,$height*2);
+
+ if($morph)
+ morphImage($background,$width*2,$height*2);
+
+ imagecopy($image,$background,0,0,30,30,$width,$height);
+
+ if(!$opaque)
+ imagecolortransparent($image,$white);
+}
+
+function addNoise($image,$width,$height)
+{
+ for($x=0;$x<$width;++$x)
+ {
+ for($y=0;$y<$height;++$y)
+ {
+ if(rand(0,100)<25)
+ {
+ $color=imagecolorallocate($image,rand(150,220),rand(150,220),rand(150,220));
+ imagesetpixel($image,$x,$y,$color);
+ imagecolordeallocate($image,$color);
+ }
+ }
+ }
+}
+
+function addGrid($image,$width,$height)
+{
+ for($i=0;$i<$width;$i+=rand(15,25))
+ {
+ imagesetthickness($image,rand(2,6));
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ imageline($image,$i+rand(-10,20),0,$i+rand(-10,20),$height,$color);
+ imagecolordeallocate($image,$color);
+ }
+ for($i=0;$i<$height;$i+=rand(15,25))
+ {
+ imagesetthickness($image,rand(2,6));
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ imageline($image,0,$i+rand(-10,20),$width,$i+rand(-10,20),$color);
+ imagecolordeallocate($image,$color);
+ }
+}
+
+function addScribble($image,$width,$height)
+{
+ for($i=0;$i<8;$i++)
+ {
+ $color=imagecolorallocate($image,rand(100,180),rand(100,180),rand(100,180));
+ $points=array();
+ for($j=1;$j<rand(5,10);$j++)
+ {
+ $points[]=rand(2*(20*($i+1)),2*(50*($i+1)));
+ $points[]=rand(30,$height+30);
+ }
+ imagesetthickness($image,rand(2,6));
+ imagepolygon($image,$points,intval(sizeof($points)/2),$color);
+ imagecolordeallocate($image,$color);
+ }
+}
+
+function morphImage($image,$width,$height)
+{
+ $tempImage=imagecreatetruecolor($width,$height);
+ $chunk=rand(1,5);
+ for($x=$y=0;$x<$width;$x+=$chunk)
+ {
+ $chunk=rand(1,5);
+ $y+=rand(-1,1);
+ if($y>=$height) $y=$height-5;
+ if($y<0) $y=5;
+ imagecopy($tempImage,$image,$x,0,$x,$y,$chunk,$height);
+ }
+ for($x=$y=0;$y<$height;$y+=$chunk)
+ {
+ $chunk=rand(1,5);
+ $x+=rand(-1,1);
+ if($x>=$width) $x=$width-5;
+ if($x<0) $x=5;
+ imagecopy($image,$tempImage,$x,$y,0,$y,$width,$chunk);
+ }
+}
+